﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// См. ОчередьЗаданийПереопределяемый.ПриПолученииСпискаШаблонов.
Процедура ПриПолученииСпискаШаблонов(ШаблоныЗаданий) Экспорт
	
	ШаблоныЗаданий.Добавить(Метаданные.РегламентныеЗадания.ПолучениеИОтправкаЭлектронныхПисем.Имя);
	
КонецПроцедуры

Функция ВложенияЭлектронногоПисьма(Письмо, ИдентификаторФормы) Экспорт
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Наименование", ОбщегоНазначения.ОписаниеТипаСтрока(256));
	Результат.Колонки.Добавить("ИДФайлаЭлектронногоПисьма", ОбщегоНазначения.ОписаниеТипаСтрока(32));
	Результат.Колонки.Добавить("Ссылка");
	
	Вложения = ПолучитьВложенияЭлектронногоПисьма(Письмо, Ложь);
	Для каждого Вложения Из Вложения Цикл
		
		НовоеВложения                           = Результат.Добавить();
		НовоеВложения.Наименование              = Вложения.ИмяФайла;
		НовоеВложения.ИДФайлаЭлектронногоПисьма = Вложения.ИДФайлаЭлектронногоПисьма;
		НовоеВложения.Ссылка                    = Вложения.Ссылка;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ЯвляетсяПисьмомИлиСообщением(Ссылка) Экспорт
	
	ТипОбъекта = ТипЗнч(Ссылка);
	
	Возврат ТипОбъекта = Тип("ДокументСсылка.ЭлектронноеПисьмоВходящее")
		ИЛИ ТипОбъекта = Тип("ДокументСсылка.ЭлектронноеПисьмоИсходящее")
		ИЛИ ТипОбъекта = Тип("ДокументСсылка.СообщениеSMS");
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

////////////////////////////////////////////////////////////////////////////////
// Получение и отправка писем

Процедура ПолучениеИОтправкаЭлектронныхПисем() Экспорт
	
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.ПолучениеИОтправкаЭлектронныхПисем);
	
	Если НЕ ПолучитьФункциональнуюОпцию("ИспользоватьПочтовыйКлиент") Тогда
		Возврат;
	КонецЕсли;
		
	УстановитьПривилегированныйРежим(Истина);
	
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), 
		УровеньЖурналаРегистрации.Информация, , ,
		НСтр("ru = 'Начато регламентное получение и отправка электронной почты'", ОбщегоНазначения.КодОсновногоЯзыка()));
		
	ПолученныеПисьма = ПолученныеПисьма();
	ЗагрузитьЭлектронныеПисьма(ПолученныеПисьма);
	ОтправитьЭлектронныеПисьма(ПолученныеПисьма.ПисьмаДляОпределенияПапок, ПолученныеПисьма.ВсеПолученныеПисьма);
	
	Взаимодействия.ЗаполнитьКонтактыМассиваВзаимодействий(ПолученныеПисьма.ВсеПолученныеПисьма);
	Взаимодействия.УстановитьПапкиДляМассиваПисем(ПолученныеПисьма.ПисьмаДляОпределенияПапок);
	Взаимодействия.РассчитатьРассмотреноПоПредметам(ПолученныеПисьма.ВсеПолученныеПисьма);
	Взаимодействия.РассчитатьРассмотреноПоКонтактам(ПолученныеПисьма.ВсеПолученныеПисьма);

	ОтправитьУведомленияОПрочтении(Ложь);
	
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), 
		УровеньЖурналаРегистрации.Информация, , ,
		НСтр("ru = 'Закончено регламентное получение и отправка электронной почты'", ОбщегоНазначения.КодОсновногоЯзыка()));
	
КонецПроцедуры

Функция ЗагрузитьЭлектронныеПисьма(ПолученныеПисьма)
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	УчетныеЗаписиЭлектроннойПочты.Ссылка                                                        КАК Ссылка,
	|	УчетныеЗаписиЭлектроннойПочты.АдресЭлектроннойПочты                                         КАК АдресЭлектроннойПочты,
	|	УчетныеЗаписиЭлектроннойПочты.Наименование                                                  КАК Наименование,
	|	ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.ПомещатьПисьмоВПапкуПисьмаОснования, ЛОЖЬ) КАК ПомещатьПисьмоВПапкуПисьмаОснования,
	|	ВЫБОР
	|		КОГДА УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)
	|			ТОГДА ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.ОтветственныйЗаОбработкуПисем, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка))
	|		ИНАЧЕ УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи
	|	КОНЕЦ                                                                                       КАК ОтветственныйЗаОбработкуПисем,
	|	УчетныеЗаписиЭлектроннойПочты.ОставлятьКопииСообщенийНаСервере                              КАК ОставлятьКопии,
	|	УчетныеЗаписиЭлектроннойПочты.ПериодХраненияСообщенийНаСервере                              КАК ОставлятьДней,
	|	УчетныеЗаписиЭлектроннойПочты.ИмяПользователя                                               КАК ИмяПользователя,
	|	УчетныеЗаписиЭлектроннойПочты.ПротоколВходящейПочты                                         КАК ПротоколВходящейПочты,
	|	ЕСТЬNULL(ДатыПоследнейЗагрузкиПочтовыхСообщений.ДатаЗагрузкиПисем, ДАТАВРЕМЯ(1, 1, 1))      КАК ДатаЗагрузкиПисем,
	|	ВЫБОР
	|		КОГДА УчетныеЗаписиЭлектроннойПочты.ПротоколВходящейПочты = ""IMAP""
	|			ТОГДА ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.ОбработкаПисемВыполняетсяВДругомПочтовомКлиенте, ЛОЖЬ)
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ                                                                                        КАК ОбработкаПисемВедетсяВДругомПочтовомКлиенте
	|ИЗ
	|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиУчетныхЗаписейЭлектроннойПочты КАК НастройкиУчетныхЗаписейЭлектроннойПочты
	|		ПО (НастройкиУчетныхЗаписейЭлектроннойПочты.УчетнаяЗаписьЭлектроннойПочты = УчетныеЗаписиЭлектроннойПочты.Ссылка)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДатыПоследнейЗагрузкиПочтовыхСообщений КАК ДатыПоследнейЗагрузкиПочтовыхСообщений
	|		ПО (ДатыПоследнейЗагрузкиПочтовыхСообщений.УчетнаяЗапись = УчетныеЗаписиЭлектроннойПочты.Ссылка)
	|ГДЕ
	|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьДляПолучения
	|	И НЕ ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.НеИспользоватьВоВстроенномПочтовомКлиенте, ЛОЖЬ)
	|	И УчетныеЗаписиЭлектроннойПочты.АдресЭлектроннойПочты <> """"
	|	И УчетныеЗаписиЭлектроннойПочты.СерверВходящейПочты <> """"
	|	И НЕ УчетныеЗаписиЭлектроннойПочты.ПометкаУдаления
	|	И ВЫБОР
	|		КОГДА &РазделениеВключено
	|			ТОГДА ВЫБОР 
	|				КОГДА ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.ДатаПоследнегоИспользования, ДАТАВРЕМЯ(1,1,1)) > &ДатаМесяцНазад 
	|					ТОГДА ИСТИНА
	|			ИНАЧЕ ЛОЖЬ
	|		КОНЕЦ
	|		ИНАЧЕ ИСТИНА
	|	КОНЕЦ";
	
	Запрос.УстановитьПараметр("ДатаМесяцНазад",     ДобавитьМесяц(НачалоДня(ТекущаяДатаСеанса()), - 1));
	Запрос.УстановитьПараметр("РазделениеВключено", ОбщегоНазначения.РазделениеВключено());
	
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Получено = 0;
		ПолученныеПисьма.ПолученныеПисьмаПоУчетнойЗаписи.Очистить();
		// @skip-check query-in-loop - Порционная загрузка писем из разных почтовых ящиков.
		ПолучитьПисьма(Выборка, Ложь, Получено, ПолученныеПисьма);
		// @skip-check query-in-loop - Порционная загрузка писем из разных почтовых ящиков.
		ОпределитьЗагруженныеРанееПодчиненныеПисьма(Выборка.Ссылка, ПолученныеПисьма.ПолученныеПисьмаПоУчетнойЗаписи);
	КонецЦикла;

	Возврат Выборка.Ссылка;
	
КонецФункции

Процедура ОтправитьЭлектронныеПисьма(ПисьмаДляОпределенияПапок, ВсеПолученныеПисьма)
	
	Запрос = Новый Запрос;
	Запрос.Текст = "
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоИсходящее.Ссылка                                                  КАК Ссылка,
	|	ПРЕДСТАВЛЕНИЕ(ЭлектронноеПисьмоИсходящее.Ссылка)                                   КАК ПредставлениеПисьма,
	|	ЭлектронноеПисьмоИсходящее.УдалятьПослеОтправки                                    КАК УдалятьПослеОтправки,
	|	ЭлектронноеПисьмоИсходящее.УчетнаяЗапись                                           КАК УчетнаяЗапись,
	|	ЕСТЬNULL(ПапкиЭлектронныхПисем.ПредопределеннаяПапка, ИСТИНА)                      КАК ТребуетсяОпределениеПапки,
	|	ЕСТЬNULL(НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма.КоличествоПопыток, 0) КАК КоличествоПопыток
	|ИЗ
	|	Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
	|		ПО ЭлектронноеПисьмоИсходящее.УчетнаяЗапись = УчетныеЗаписиЭлектроннойПочты.Ссылка
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействий
	|			ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПапкиЭлектронныхПисем КАК ПапкиЭлектронныхПисем
	|			ПО ПредметыПапкиВзаимодействий.ПапкаЭлектронногоПисьма = ПапкиЭлектронныхПисем.Ссылка
	|		ПО (ПредметыПапкиВзаимодействий.Взаимодействие = ЭлектронноеПисьмоИсходящее.Ссылка)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма КАК НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма
	|		ПО (НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма.Письмо = ЭлектронноеПисьмоИсходящее.Ссылка)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиУчетныхЗаписейЭлектроннойПочты КАК НастройкиУчетныхЗаписейЭлектроннойПочты
	|		ПО (НастройкиУчетныхЗаписейЭлектроннойПочты.УчетнаяЗаписьЭлектроннойПочты = УчетныеЗаписиЭлектроннойПочты.Ссылка)
	|ГДЕ
	|	НЕ ЭлектронноеПисьмоИсходящее.ПометкаУдаления
	|	И УчетныеЗаписиЭлектроннойПочты.АдресЭлектроннойПочты <> """"
	|	И УчетныеЗаписиЭлектроннойПочты.СерверИсходящейПочты <> """"
	|	И УчетныеЗаписиЭлектроннойПочты.ИспользоватьДляОтправки
	|	И ЭлектронноеПисьмоИсходящее.СтатусПисьма = ЗНАЧЕНИЕ(Перечисление.СтатусыИсходящегоЭлектронногоПисьма.Исходящее)
	|	И ВЫБОР
	|			КОГДА ЭлектронноеПисьмоИсходящее.ДатаКогдаОтправить = ДАТАВРЕМЯ(1, 1, 1)
	|				ТОГДА ИСТИНА
	|			ИНАЧЕ ЭлектронноеПисьмоИсходящее.ДатаКогдаОтправить < &ТекущаяДата
	|		КОНЕЦ
	|	И ВЫБОР
	|			КОГДА ЭлектронноеПисьмоИсходящее.ДатаАктуальностиОтправки = ДАТАВРЕМЯ(1, 1, 1)
	|				ТОГДА ИСТИНА
	|			ИНАЧЕ ЭлектронноеПисьмоИсходящее.ДатаАктуальностиОтправки > &ТекущаяДата
	|		КОНЕЦ
	|	И ЕСТЬNULL(НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма.КоличествоПопыток, 0) < 5
	|	И ВЫБОР
	|		КОГДА &РазделениеВключено
	|			ТОГДА ВЫБОР 
	|				КОГДА ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.ДатаПоследнегоИспользования, ДАТАВРЕМЯ(1,1,1)) > &ДатаМесяцНазад 
	|					ТОГДА ИСТИНА
	|			ИНАЧЕ ЛОЖЬ
	|		КОНЕЦ
	|		ИНАЧЕ ИСТИНА
	|	КОНЕЦ
	|ИТОГИ ПО
	|	УчетнаяЗапись";
	
	Запрос.УстановитьПараметр("ТекущаяДата",        ТекущаяДатаСеанса());
	Запрос.УстановитьПараметр("ДатаМесяцНазад",     ДобавитьМесяц(НачалоДня(ТекущаяДатаСеанса()), - 1));
	Запрос.УстановитьПараметр("РазделениеВключено", ОбщегоНазначения.РазделениеВключено());
	
	ОтправитьПисьма(Запрос, ВсеПолученныеПисьма, ПисьмаДляОпределенияПапок);
	
КонецПроцедуры

Процедура ОтправитьПисьма(Запрос, ВсеПолученныеПисьма, ПисьмаДляОпределенияПапок, ОтправленоПисем = 0, ЕстьОшибки = Ложь, Интерактивно = Ложь)
	
	ВыборкаУчетныеЗаписи = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	УстановитьПривилегированныйРежим(Истина);
	
	РазделениеВключено = ОбщегоНазначения.РазделениеВключено();
	
	Пока ВыборкаУчетныеЗаписи.Следующий() Цикл
		УчетнаяЗапись = ВыборкаУчетныеЗаписи.УчетнаяЗапись;
		// @skip-check query-in-loop - Порционная загрузка писем из разных почтовых ящиков.
		Если Не ЗаблокироватьУчетнуюЗапись(УчетнаяЗапись) Тогда
			Продолжить;
		КонецЕсли;
		
		Если Не РазделениеВключено Тогда
			РегистрыСведений.НастройкиУчетныхЗаписейЭлектроннойПочты.ОбновитьДатуИспользованияУчетнойЗаписи(УчетнаяЗапись);
		КонецЕсли;
		
		Письма = Новый Массив;
		СсылкиПисем = Новый Соответствие;
		
		ВыборкаПисьма = ВыборкаУчетныеЗаписи.Выбрать();
		Пока ВыборкаПисьма.Следующий() Цикл
			
			ПисьмоОбъект = ВыборкаПисьма.Ссылка.ПолучитьОбъект();
			ПараметрыПисьма = Взаимодействия.ПараметрыПисьмаДляОтправки(ПисьмоОбъект);
			Попытка
				Письмо = РаботаСПочтовымиСообщениями.ПодготовитьПисьмо(УчетнаяЗапись, ПараметрыПисьма);
			Исключение
				
				ШаблонСообщенияОбОшибке = НСтр("ru = 'Письмо %1 не подготовлено к отправке по причине:
					|%2'", ОбщегоНазначения.КодОсновногоЯзыка());
				
				ТекстСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					ШаблонСообщенияОбОшибке, 
					Взаимодействия.ПредставлениеПисьма(ПисьмоОбъект.Тема, ПисьмоОбъект.Дата),
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщенияОбОшибке);
				
				МенеджерЗаписи = РегистрыСведений.НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма.СоздатьМенеджерЗаписи();
				МенеджерЗаписи.Письмо            = ВыборкаПисьма.Ссылка;
				МенеджерЗаписи.КоличествоПопыток = 5;
				МенеджерЗаписи.ИнформацияООшибке = ТекстСообщенияОбОшибке;
				МенеджерЗаписи.Записать();
				
				Продолжить;
				
			КонецПопытки;
			
			Письма.Добавить(Письмо);
			СсылкиПисем.Вставить(ВыборкаПисьма.Ссылка, Письмо);
			
		КонецЦикла;
		
		ТекстОшибки = Неопределено;
		Попытка
			РезультатОтправки = РаботаСПочтовымиСообщениями.ОтправитьПисьма(УчетнаяЗапись, Письма, ТекстОшибки);
			СнятьБлокировкуУчетнойЗаписиДляПолучения(УчетнаяЗапись);
		Исключение
			СнятьБлокировкуУчетнойЗаписиДляПолучения(УчетнаяЗапись);
			
			ШаблонСообщенияОбОшибке = НСтр("ru = 'Не удалось подключиться к почте %1 по причине:
				|%2'", ОбщегоНазначения.КодОсновногоЯзыка());
			
			ТекстСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщенияОбОшибке, 
				УчетнаяЗапись, РаботаСПочтовымиСообщениями.РасширенноеПредставлениеОшибки(ИнформацияОбОшибке(), ОбщегоНазначения.КодОсновногоЯзыка()));
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщенияОбОшибке);
			Если Не ЗначениеЗаполнено(РезультатОтправки) Тогда
				Продолжить;
			КонецЕсли;
		КонецПопытки;
		
		ТекстыОшибок = Новый Массив;
		ВыборкаПисьма = ВыборкаУчетныеЗаписи.Выбрать();
		Пока ВыборкаПисьма.Следующий() Цикл
			ПисьмоСсылка = ВыборкаПисьма.Ссылка;
			РезультатОтправкиПисьма = РезультатОтправки[СсылкиПисем[ПисьмоСсылка]];
			ОшибочныеПолучатели = Неопределено;
			Если РезультатОтправкиПисьма <> Неопределено Тогда
				ОшибочныеПолучатели = РезультатОтправкиПисьма.ОшибочныеПолучатели;
				Если ЗначениеЗаполнено(ОшибочныеПолучатели) Тогда
					ПараметрыОбработкиОшибки = ПараметрыОбработкиОшибкиОтправки();
					ПараметрыОбработкиОшибки.ПисьмоОбъект                      = ВыборкаПисьма.Ссылка.ПолучитьОбъект();
					ПараметрыОбработкиОшибки.Ссылка                            = ВыборкаПисьма.Ссылка;
					ПараметрыОбработкиОшибки.ПредставлениеПисьма               = ВыборкаПисьма.ПредставлениеПисьма;
					ПараметрыОбработкиОшибки.КоличествоПопыток                 = ВыборкаПисьма.КоличествоПопыток;
					ПараметрыОбработкиОшибки.ИнкрементироватьКоличествоПопыток = Истина;
					ПараметрыОбработкиОшибки.СообщатьПользователю              = Интерактивно;
					
					РезультатОбработкиОшибки = ОбработатьОшибкуОтправкиПисьма(ПараметрыОбработкиОшибки, ОшибочныеПолучатели);
					Если Не РезультатОбработкиОшибки.ПисьмоОтправлено Тогда
						Продолжить;
					КонецЕсли;
				КонецЕсли;
				
				ОтправленоПисем = ОтправленоПисем + 1;
				УдалятьПослеОтправки = ВыборкаПисьма.УдалятьПослеОтправки;
				
				ТекстОшибки = ПослеВыполненияОтправкиПисьма(ПисьмоСсылка, РезультатОтправкиПисьма.ИдентификаторПисьмаSMTP, 
				РезультатОтправкиПисьма.ИдентификаторПисьмаIMAP, УдалятьПослеОтправки, Ложь);
				
				Если ЗначениеЗаполнено(ТекстОшибки) Тогда
					ТекстыОшибок.Добавить(ТекстОшибки);
					Продолжить;
				КонецЕсли;
				
				Если Не ВыборкаПисьма.УдалятьПослеОтправки Тогда
					Если ВыборкаПисьма.ТребуетсяОпределениеПапки Тогда
						ПисьмаДляОпределенияПапок.Добавить(ВыборкаПисьма.Ссылка);
					КонецЕсли;
					ВсеПолученныеПисьма.Добавить(ВыборкаПисьма.Ссылка);
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		
		Если ЗначениеЗаполнено(ТекстыОшибок) Тогда
			ВызватьИсключение СтрСоединить(ТекстыОшибок, Символы.ПС);
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ПослеВыполненияОтправкиПисьма(Ссылка, ИдентификаторСообщения, ИдентификаторСообщенияОтправкаIMAP, УдалятьПослеОтправки, ВызыватьИсключение = Истина)

	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("Документ.ЭлектронноеПисьмоИсходящее");
		ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка);
		Блокировка.Заблокировать();
		
		Если УдалятьПослеОтправки Тогда
			ПисьмоОбъект = Ссылка.ПолучитьОбъект();
			ПисьмоОбъект.Удалить();
		Иначе
			ПисьмоОбъект = Ссылка.ПолучитьОбъект(); // ДокументОбъект.ЭлектронноеПисьмоИсходящее
			ПисьмоОбъект.ИдентификаторСообщения             = ИдентификаторСообщения;
			ПисьмоОбъект.ИдентификаторСообщенияОтправкаIMAP = ИдентификаторСообщенияОтправкаIMAP;
			
			ПисьмоОбъект.СтатусПисьма                       = Перечисления.СтатусыИсходящегоЭлектронногоПисьма.Отправлено;
			ПисьмоОбъект.Размер                             = Взаимодействия.ОценитьРазмерИсходящегоЭлектронногоПисьма(ПисьмоОбъект.Ссылка);
			ПисьмоОбъект.ДатаОтправления                    = ТекущаяДатаСеанса();
			ПисьмоОбъект.ДополнительныеСвойства.Вставить("НеЗаписыватьКонтакты", Истина);
			ПисьмоОбъект.Записать(РежимЗаписиДокумента.Запись);
		КонецЕсли;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		Если ВызыватьИсключение Тогда
			ВызватьИсключение;
		КонецЕсли;
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, Ссылка.Метаданные(),
			ПисьмоОбъект, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
		Возврат ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	КонецПопытки;
	
	Возврат "";
	
КонецФункции

// Возвращаемое значение:
//   Структура:
//     * ПисьмоОбъект                      - ДокументОбъект.ЭлектронноеПисьмоИсходящее - отправляемое письмо.
//     * Ссылка                            - ДокументСсылка.ЭлектронноеПисьмоИсходящее - ссылка на отправляемое письмо.
//     * ПредставлениеПисьма               - Строка
//     * КоличествоПопыток                 - Число - количество уже совершенных попыток по отправке письма.
//     * ИнкрементироватьКоличествоПопыток - Булево
//     * СообщатьПользователю              - Булево - признак того, что нужно вывести сообщение пользователю.
//
Функция ПараметрыОбработкиОшибкиОтправки() Экспорт
	
	Параметры = Новый Структура;
	Параметры.Вставить("ПисьмоОбъект",                       Неопределено);
	Параметры.Вставить("Ссылка",                             Неопределено);
	Параметры.Вставить("ПредставлениеПисьма",                "");
	Параметры.Вставить("КоличествоПопыток",                  0);
	Параметры.Вставить("ИнкрементироватьКоличествоПопыток" , Ложь);
	Параметры.Вставить("СообщатьПользователю",               Ложь);
	
	Возврат Параметры;
	
КонецФункции

// Параметры:
//  ПараметрыОбработкиОшибки - см. ПараметрыОбработкиОшибкиОтправки
//  ОшибочныеПолучатели      - Массив 
// 
// Возвращаемое значение:
//  Структура:
//    * ТекстСообщения - Строка - текст сообщения об ошибке
//    * ПисьмоОтправлено - Булево - признак того, что письмо было отправлено
//
Функция ОбработатьОшибкуОтправкиПисьма(ПараметрыОбработкиОшибки, Знач ОшибочныеПолучатели) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ТекстСообщения", "");
	Результат.Вставить("ПисьмоОтправлено", Ложь);
	
	РезультатАнализа = РезультатАнализаОшибочныхПолучателей(ПараметрыОбработкиОшибки.ПисьмоОбъект, ОшибочныеПолучатели);
	ВсеАдресатыПисьмаОтвергнутыСервером           = РезультатАнализа.ВсеАдресатыПисьмаОтвергнутыСервером;
	ПредставлениеОшибочныхАдресатов               = РезультатАнализа.ПредставлениеОшибочныхАдресатов;
	
	Если Не ВсеАдресатыПисьмаОтвергнутыСервером Тогда
		ШаблонСообщенияОбОшибке = НСтр("ru = 'Следующие адресаты письма ""%1"" не приняты почтовым сервером:
			|%2. Письмо отправлено остальным адресатам.'", ОбщегоНазначения.КодОсновногоЯзыка());
	Иначе
		ШаблонСообщенияОбОшибке = НСтр("ru = 'Не удалось отправить письмо ""%1"".
		|Следующие адресаты письма не приняты почтовым сервером:
			|%2.'", ОбщегоНазначения.КодОсновногоЯзыка());
	КонецЕсли;
	ТекстСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщенияОбОшибке,
		ПараметрыОбработкиОшибки.ПредставлениеПисьма, ПредставлениеОшибочныхАдресатов);
	
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка,,
		ПараметрыОбработкиОшибки.Ссылка, ТекстСообщенияОбОшибке);
	
	Результат.ТекстСообщения = ТекстСообщенияОбОшибке;
	
	Если ПараметрыОбработкиОшибки.СообщатьПользователю Тогда
		ОбщегоНазначения.СообщитьПользователю(ТекстСообщенияОбОшибке, ПараметрыОбработкиОшибки.Ссылка);
	КонецЕсли;
	
	Если ВсеАдресатыПисьмаОтвергнутыСервером Тогда
		
		ПисьмоОбъект = ПараметрыОбработкиОшибки.ПисьмоОбъект; // ДокументОбъект.ЭлектронноеПисьмоИсходящее
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(),
		                        УровеньЖурналаРегистрации.Ошибка, 
		                        ПисьмоОбъект.Ссылка.Метаданные(), 
		                        ПараметрыОбработкиОшибки.Ссылка, 
		                        ТекстСообщенияОбОшибке);
		
		Если ПараметрыОбработкиОшибки.ИнкрементироватьКоличествоПопыток Тогда
			
			МенеджерЗаписи = РегистрыСведений.НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма.СоздатьМенеджерЗаписи();
			МенеджерЗаписи.Письмо = ПараметрыОбработкиОшибки.Ссылка;
			МенеджерЗаписи.КоличествоПопыток = ?(ВсеАдресатыПисьмаОтвергнутыСервером, 5, ПараметрыОбработкиОшибки.КоличествоПопыток + 1);
			МенеджерЗаписи.ИнформацияООшибке = ТекстСообщенияОбОшибке;
			МенеджерЗаписи.Записать();
		
		КонецЕсли;
		Возврат Результат;
		
	КонецЕсли;
	
	Результат.ПисьмоОтправлено = Истина;
	
	Возврат Результат;

КонецФункции

Процедура ОтправитьУведомленияОПрочтении(ДляТекущегоПользователя)
	
	ТекстЗапроса = 
		"ВЫБРАТЬ
		|	УведомленияОПрочтении.Письмо КАК Письмо,
		|	ПРЕДСТАВЛЕНИЕ(УведомленияОПрочтении.Письмо) КАК ПредставлениеПисьма,
		|	УведомленияОПрочтении.ДатаПрочтения КАК ДатаПрочтения,
		|	ЭлектронноеПисьмоВходящее.АдресаУведомленияОПрочтении.(
		|		Адрес КАК Адрес,
		|		Представление КАК Представление,
		|		Контакт КАК Контакт
		|	) КАК АдресаУведомленияОПрочтении,
		|	ЭлектронноеПисьмоВходящее.УчетнаяЗапись КАК УчетнаяЗапись,
		|	ЭлектронноеПисьмоВходящее.ОтправительПредставление КАК ОтправительПредставление,
		|	ЭлектронноеПисьмоВходящее.ОтправительАдрес КАК ОтправительАдрес,
		|	ЭлектронноеПисьмоВходящее.Дата КАК Дата,
		|	УчетныеЗаписиЭлектроннойПочты.ИмяПользователя КАК ИмяПользователя,
		|	УчетныеЗаписиЭлектроннойПочты.АдресЭлектроннойПочты КАК АдресЭлектроннойПочты,
		|	ЭлектронноеПисьмоВходящее.Тема КАК Тема,
		|	УведомленияОПрочтении.Пользователь КАК Пользователь
		|ИЗ
		|	РегистрСведений.УведомленияОПрочтении КАК УведомленияОПрочтении
		|		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоВходящее КАК ЭлектронноеПисьмоВходящее
		|			ЛЕВОЕ СОЕДИНЕНИЕ Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
		|			ПО ЭлектронноеПисьмоВходящее.УчетнаяЗапись = УчетныеЗаписиЭлектроннойПочты.Ссылка
		|		ПО УведомленияОПрочтении.Письмо = ЭлектронноеПисьмоВходящее.Ссылка
		|ГДЕ
		|	УведомленияОПрочтении.ТребуетсяОтправка
		|	И &ДляТекущегоПользователя
		|ИТОГИ ПО
		|	УчетнаяЗапись";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДляТекущегоПользователя", 
		?(ДляТекущегоПользователя, "УведомленияОПрочтении.Пользователь = &Пользователь", "ИСТИНА"));
	Запрос = Новый Запрос(ТекстЗапроса);
	Если ДляТекущегоПользователя Тогда
		Запрос.УстановитьПараметр("Пользователь", Пользователи.ТекущийПользователь());
	КонецЕсли;
	
	ВыборкаУчетныеЗаписи = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	Пока ВыборкаУчетныеЗаписи.Следующий() Цикл
		
		УчетнаяЗапись = ВыборкаУчетныеЗаписи.УчетнаяЗапись;
		Письма = Новый Массив;
		СсылкиПисем = Новый Соответствие;
		
		ВыборкаПисьма = ВыборкаУчетныеЗаписи.Выбрать();
		Пока ВыборкаПисьма.Следующий() Цикл
			ПараметрыПисьма = Новый Структура;
			
			Взаимодействия.ДобавитьВПараметрАдресатов(ВыборкаПисьма, ПараметрыПисьма, "Кому", "АдресаУведомленияОПрочтении");
			
			ПараметрыПисьма.Вставить("Тема",НСтр("ru = 'Уведомление о прочтении'") + " / " +"Reading Confirmation");
			ПараметрыПисьма.Вставить("Тело",СформироватьТекстУведомленияОПрочтении(ВыборкаПисьма));
			ПараметрыПисьма.Вставить("Кодировка","UTF-8");
			ПараметрыПисьма.Вставить("Важность", ВажностьИнтернетПочтовогоСообщения.Обычная);
			ПараметрыПисьма.Вставить("ТипТекста", Перечисления.ТипыТекстовЭлектронныхПисем.ПростойТекст);
			ПараметрыПисьма.Вставить("ОбрабатыватьТексты", Ложь);
			
			Письмо = РаботаСПочтовымиСообщениями.ПодготовитьПисьмо(УчетнаяЗапись, ПараметрыПисьма);
			Письма.Добавить(Письмо);
			
			СсылкиПисем.Вставить(Письмо, ВыборкаПисьма.Письмо);
		КонецЦикла;
		
		ОтправленныеПисьма = РаботаСПочтовымиСообщениями.ОтправитьПисьма(УчетнаяЗапись, Письма);
		Для Каждого Письмо Из СсылкиПисем Цикл
			Если ОтправленныеПисьма[Письмо.Ключ] = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			Ссылка = Письмо.Значение;
			УстановитьПризнакОтправкиУведомления(Ссылка, Ложь);
		КонецЦикла;
		
	КонецЦикла;

КонецПроцедуры

// Выполняет получение электронной почты по доступным для пользователя учетным записям.
//
// Параметры:
//   Результат - Структура:
//   * Получено               - Число - в данный параметр будет возвращено количество полученных писем.
//   * ДоступноУчетныхЗаписей - Число - в данный параметр будет возвращено количество доступных пользователю учетных
//                                   записей.
//   * ЕстьОшибки             - Булево - признак наличия ошибок при получении писем.
//
Процедура ЗагрузитьПочтуПользователя(Результат)
	
	ДлительныеОперации.СообщитьПрогресс(, НСтр("ru = 'Получение почты'"));
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	УчетныеЗаписиЭлектроннойПочты.Ссылка                                                        КАК Ссылка,
	|	УчетныеЗаписиЭлектроннойПочты.АдресЭлектроннойПочты                                         КАК АдресЭлектроннойПочты,
	|	УчетныеЗаписиЭлектроннойПочты.Наименование                                                  КАК Наименование,
	|	ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.ПомещатьПисьмоВПапкуПисьмаОснования, ЛОЖЬ) КАК ПомещатьПисьмоВПапкуПисьмаОснования,
	|	ВЫБОР
	|		КОГДА УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)
	|			ТОГДА ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.ОтветственныйЗаОбработкуПисем, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка))
	|		ИНАЧЕ УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи
	|	КОНЕЦ КАК ОтветственныйЗаОбработкуПисем,
	|	УчетныеЗаписиЭлектроннойПочты.ОставлятьКопииСообщенийНаСервере КАК ОставлятьКопии,
	|	УчетныеЗаписиЭлектроннойПочты.ПериодХраненияСообщенийНаСервере КАК ОставлятьДней,
	|	УчетныеЗаписиЭлектроннойПочты.ПротоколВходящейПочты КАК ПротоколВходящейПочты,
	|	УчетныеЗаписиЭлектроннойПочты.ИмяПользователя КАК ИмяПользователя,
	|	ЕСТЬNULL(ДатыПоследнейЗагрузкиПочтовыхСообщений.ДатаЗагрузкиПисем, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаЗагрузкиПисем,
	|	ВЫБОР
	|		КОГДА УчетныеЗаписиЭлектроннойПочты.ПротоколВходящейПочты = ""IMAP""
	|			ТОГДА ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.ОбработкаПисемВыполняетсяВДругомПочтовомКлиенте, ЛОЖЬ)
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК ОбработкаПисемВедетсяВДругомПочтовомКлиенте
	|ИЗ
	|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиУчетныхЗаписейЭлектроннойПочты КАК НастройкиУчетныхЗаписейЭлектроннойПочты
	|		ПО (НастройкиУчетныхЗаписейЭлектроннойПочты.УчетнаяЗаписьЭлектроннойПочты = УчетныеЗаписиЭлектроннойПочты.Ссылка)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДатыПоследнейЗагрузкиПочтовыхСообщений КАК ДатыПоследнейЗагрузкиПочтовыхСообщений
	|		ПО (ДатыПоследнейЗагрузкиПочтовыхСообщений.УчетнаяЗапись = УчетныеЗаписиЭлектроннойПочты.Ссылка)
	|ГДЕ
	|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьДляПолучения
	|	И НЕ УчетныеЗаписиЭлектроннойПочты.ПометкаУдаления
	|	И НЕ ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.НеИспользоватьВоВстроенномПочтовомКлиенте, ЛОЖЬ)";
	
	Выборка = Запрос.Выполнить().Выбрать();

	Результат.ПолученоПисем = 0;
	Результат.ДоступноУчетныхЗаписей = Выборка.Количество();
	Если Результат.ДоступноУчетныхЗаписей = 0 Тогда
		ОбщегоНазначения.СообщитьПользователю(НСтр("ru = 'Нет доступных учетных записей для получения почты.'"));
		Результат.ЕстьОшибки = Истина;
		Возврат;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	РазделениеВключено = ОбщегоНазначения.РазделениеВключено();
	
	Пока Выборка.Следующий() Цикл
		
		Если РазделениеВключено Тогда
			РегистрыСведений.НастройкиУчетныхЗаписейЭлектроннойПочты.ОбновитьДатуИспользованияУчетнойЗаписи(Выборка.Ссылка);
		КонецЕсли;
		
		Получено = 0;
		ПолученныеПисьма = ПолученныеПисьма();
		
		// @skip-check query-in-loop - Порционная загрузка писем из разных почтовых ящиков.
		ПолучитьПисьма(Выборка, Результат.ЕстьОшибки, Получено, ПолученныеПисьма);
		Результат.ПолученоПисем = Результат.ПолученоПисем + Получено;
		
		// @skip-check query-in-loop - Порционная загрузка писем из разных почтовых ящиков.
		ОпределитьЗагруженныеРанееПодчиненныеПисьма(Выборка.Ссылка, ПолученныеПисьма.ПолученныеПисьмаПоУчетнойЗаписи);
		Взаимодействия.ЗаполнитьКонтактыМассиваВзаимодействий(ПолученныеПисьма.ВсеПолученныеПисьма);
		Взаимодействия.УстановитьПапкиДляМассиваПисем(ПолученныеПисьма.ПисьмаДляОпределенияПапок);
		Взаимодействия.РассчитатьРассмотреноПоПредметам(ПолученныеПисьма.ВсеПолученныеПисьма);
		Взаимодействия.РассчитатьРассмотреноПоКонтактам(ПолученныеПисьма.ВсеПолученныеПисьма);
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ОтправитьПочтуПользователя(Результат)
	
	ДлительныеОперации.СообщитьПрогресс(, НСтр("ru = 'Отправка почты'"));
	
	Запрос = Новый Запрос;
	Запрос.Текст = "
	|ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	УчетныеЗаписиЭлектроннойПочты.Ссылка                                               КАК УчетнаяЗапись,
	|	ЭлектронноеПисьмоИсходящее.Ссылка                                                  КАК Ссылка,
	|	ПРЕДСТАВЛЕНИЕ(ЭлектронноеПисьмоИсходящее.Ссылка)                                   КАК ПредставлениеПисьма,
	|	ЭлектронноеПисьмоИсходящее.УдалятьПослеОтправки                                    КАК УдалятьПослеОтправки,
	|	ЕСТЬNULL(ПапкиЭлектронныхПисем.ПредопределеннаяПапка, ИСТИНА)                      КАК ТребуетсяОпределениеПапки,
	|	ЕСТЬNULL(НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма.КоличествоПопыток, 0) КАК КоличествоПопыток
	|ИЗ
	|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
	|		ПО ЭлектронноеПисьмоИсходящее.УчетнаяЗапись = УчетныеЗаписиЭлектроннойПочты.Ссылка
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействий
	|			ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПапкиЭлектронныхПисем КАК ПапкиЭлектронныхПисем
	|			ПО ПредметыПапкиВзаимодействий.ПапкаЭлектронногоПисьма = ПапкиЭлектронныхПисем.Ссылка
	|		ПО (ПредметыПапкиВзаимодействий.Взаимодействие = ЭлектронноеПисьмоИсходящее.Ссылка)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиУчетныхЗаписейЭлектроннойПочты КАК НастройкиУчетныхЗаписейЭлектроннойПочты
	|		ПО ЭлектронноеПисьмоИсходящее.УчетнаяЗапись = НастройкиУчетныхЗаписейЭлектроннойПочты.УчетнаяЗаписьЭлектроннойПочты
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма КАК НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма
	|		ПО НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма.Письмо = ЭлектронноеПисьмоИсходящее.Ссылка
	|ГДЕ
	|	НЕ ЭлектронноеПисьмоИсходящее.ПометкаУдаления
	|	И НЕ УчетныеЗаписиЭлектроннойПочты.ПометкаУдаления
	|	И ЭлектронноеПисьмоИсходящее.СтатусПисьма = ЗНАЧЕНИЕ(Перечисление.СтатусыИсходящегоЭлектронногоПисьма.Исходящее)
	|	И УчетныеЗаписиЭлектроннойПочты.ИспользоватьДляОтправки
	|	И НЕ ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.НеИспользоватьВоВстроенномПочтовомКлиенте, ЛОЖЬ)
	|	И ВЫБОР
	|			КОГДА ЭлектронноеПисьмоИсходящее.ДатаКогдаОтправить = ДАТАВРЕМЯ(1, 1, 1)
	|				ТОГДА ИСТИНА
	|			ИНАЧЕ ЭлектронноеПисьмоИсходящее.ДатаКогдаОтправить < &ТекущаяДата
	|		КОНЕЦ
	|	И ВЫБОР
	|			КОГДА ЭлектронноеПисьмоИсходящее.ДатаАктуальностиОтправки = ДАТАВРЕМЯ(1, 1, 1)
	|				ТОГДА ИСТИНА
	|			ИНАЧЕ ЭлектронноеПисьмоИсходящее.ДатаАктуальностиОтправки > &ТекущаяДата
	|		КОНЕЦ
	|	И ЕСТЬNULL(НепринятыеКОбработкеПочтовымСерверомИсходящиеПисьма.КоличествоПопыток, 0) < 5
	|ИТОГИ ПО
	|	УчетнаяЗапись";
	
	Запрос.УстановитьПараметр("Пользователь", Пользователи.ТекущийПользователь());
	Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());
	
	ПисьмаДляОпределенияПапок = Новый Массив;
	ВсеПолученныеПисьма = Новый Массив;
	Результат.ОтправленоПисем = 0;
	
	ОтправитьПисьма(Запрос, ВсеПолученныеПисьма, ПисьмаДляОпределенияПапок, Результат.ОтправленоПисем, Результат.ЕстьОшибки, Истина);
	
	Взаимодействия.УстановитьПапкиДляМассиваПисем(ПисьмаДляОпределенияПапок);
	ОтправитьУведомленияОПрочтении(Истина);
	
КонецПроцедуры

Процедура ОтправитьЗагрузитьПочтуПользователя(ПараметрыВыгрузки, АдресХранилища) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ОтправленоПисем",        0);
	Результат.Вставить("ПолученоПисем",          0);
	Результат.Вставить("ДоступноУчетныхЗаписей", 0);
	Результат.Вставить("ЕстьОшибки",             Ложь);
	
	ОтправитьПочтуПользователя(Результат);
	ЗагрузитьПочтуПользователя(Результат);
	
	ПоместитьВоВременноеХранилище(Результат, АдресХранилища);
	
КонецПроцедуры

Функция РезультатАнализаОшибочныхПолучателей(ПисьмоОбъект, ОшибочныеПолучатели)

	Результат = Новый Структура;
	Результат.Вставить("ЭтоПроблемаОтвергнутыхСерверомПочтовыхАдресов",Ложь);
	Результат.Вставить("ВсеАдресатыПисьмаОтвергнутыСервером",Ложь);
	Результат.Вставить("ПредставлениеОшибочныхАдресатов","");
	
	КоличествоОшибочныхПолучателей = ОшибочныеПолучатели.Количество();
	
	Если КоличествоОшибочныхПолучателей > 0 Тогда
		
		Результат.ЭтоПроблемаОтвергнутыхСерверомПочтовыхАдресов = Истина;
		
		МассивПолучателейПисьма = Новый Массив;
		Для Каждого СтрокаПолучателя Из ПисьмоОбъект.ПолучателиПисьма Цикл
			Если МассивПолучателейПисьма.Найти(СтрокаПолучателя.Адрес) = Неопределено Тогда
				МассивПолучателейПисьма.Добавить(СтрокаПолучателя.Адрес);
			КонецЕсли;
		КонецЦикла;
		Для Каждого СтрокаПолучателя Из ПисьмоОбъект.ПолучателиКопий Цикл
			Если МассивПолучателейПисьма.Найти(СтрокаПолучателя.Адрес) = Неопределено Тогда
				МассивПолучателейПисьма.Добавить(СтрокаПолучателя.Адрес);
			КонецЕсли;
		КонецЦикла;
		Для Каждого СтрокаПолучателя Из ПисьмоОбъект.ПолучателиСкрытыхКопий Цикл
			Если МассивПолучателейПисьма.Найти(СтрокаПолучателя.Адрес) = Неопределено Тогда
				МассивПолучателейПисьма.Добавить(СтрокаПолучателя.Адрес);
			КонецЕсли;
		КонецЦикла;
		
		КоличествоПолучателейПисьма = МассивПолучателейПисьма.Количество();
		
		Если КоличествоПолучателейПисьма = КоличествоОшибочныхПолучателей Тогда
			Результат.ВсеАдресатыПисьмаОтвергнутыСервером = Истина;
		КонецЕсли;
		
		ПредставлениеОшибочныхАдресатов = "";
		Для Каждого ОшибочныйАдресат Из ОшибочныеПолучатели Цикл
			Если Не ПустаяСтрока(ПредставлениеОшибочныхАдресатов) Тогда
				ПредставлениеОшибочныхАдресатов = ПредставлениеОшибочныхАдресатов + ", ";
			КонецЕсли;
			ПредставлениеОшибочныхАдресатов = ПредставлениеОшибочныхАдресатов + ОшибочныйАдресат.Ключ;
		КонецЦикла;
		
		Результат.ПредставлениеОшибочныхАдресатов = ПредставлениеОшибочныхАдресатов;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Заполняет ИнтернетПочтовыеАдреса в объекте ИнтернетПочтовоеСообщение по переданной таблице адресов.
//
// Параметры:
//  ТабличнаяЧасть  - ИнтернетПочтовыеАдреса - адреса, которые будут заполнены в письме.
//  Адреса          - ТаблицаЗначений - таблица, содержащая адреса для указания в письме.
//
Процедура ЗаполнитьИнтернетПочтовыеАдреса(ТабличнаяЧасть, Адреса) Экспорт
	
	Для Каждого Адрес Из Адреса Цикл
		НоваяСтрока = ТабличнаяЧасть.Добавить();
		НоваяСтрока.Адрес         = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Адрес.Адрес, "");
		НоваяСтрока.Представление = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Адрес.ОтображаемоеИмя, "");
	КонецЦикла;
	
КонецПроцедуры

Процедура ПолучитьПисьма(Знач ДанныеУчетнойЗаписи, ЕстьОшибки, Получено, ПолученныеПисьма)
	
	Если Не ЗаблокироватьУчетнуюЗапись(ДанныеУчетнойЗаписи.Ссылка) Тогда
		Возврат;
	КонецЕсли;
	
	Профиль = РаботаСПочтовымиСообщениямиСлужебный.ИнтернетПочтовыйПрофиль(ДанныеУчетнойЗаписи.Ссылка, Истина);
	Протокол = ПротоколИнтернетПочты.POP3;
	Если ДанныеУчетнойЗаписи.ПротоколВходящейПочты = "IMAP" Тогда
		Протокол = ПротоколИнтернетПочты.IMAP;
	КонецЕсли;
	
	Почта = Новый ИнтернетПочта;
	Попытка
		Почта.Подключиться(Профиль, Протокол);
	Исключение		
		СнятьБлокировкуУчетнойЗаписиДляПолучения(ДанныеУчетнойЗаписи.Ссылка);
		
		ЕстьОшибки = Истина;
		ТекстСообщенияОбОшибке = РаботаСПочтовымиСообщениями.РасширенноеПредставлениеОшибки(
			ИнформацияОбОшибке(), ОбщегоНазначения.КодОсновногоЯзыка());			
		ТекстСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось подключиться к почте %1 по причине:
				|%2'", ОбщегоНазначения.КодОсновногоЯзыка()),
				ДанныеУчетнойЗаписи.Ссылка,
				ТекстСообщенияОбОшибке);			
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщенияОбОшибке);		
		Возврат;
		
	КонецПопытки;
	
	Если Протокол = ПротоколИнтернетПочты.POP3 Тогда
		ПолучитьПочтуПоПроколуPOP3(ДанныеУчетнойЗаписи, Почта, Получено, ПолученныеПисьма);
	Иначе
		ПолучитьПочтуПоПроколуIMAP(ДанныеУчетнойЗаписи, Почта, Получено, ПолученныеПисьма);
		СинхронизироватьПризнакРассмотреноССервером(Почта, ДанныеУчетнойЗаписи, ПолученныеПисьма.ВсеПолученныеПисьма);
	КонецЕсли;
	
	Почта.Отключиться();
	
	СнятьБлокировкуУчетнойЗаписиДляПолучения(ДанныеУчетнойЗаписи.Ссылка);

КонецПроцедуры

// Параметры:
//  Почта - ИнтернетПочта
//  ДанныеУчетнойЗаписи - ВыборкаИзРезультатаЗапроса
//  ИдентификаторыПисемКЗагрузке - Массив из Строка
//  ПолученныеПисьма - см. ПолученныеПисьма
//  ВсеИдентификаторы - Массив из Строка
//
// Возвращаемое значение:
//  Число - количество полученных писем.
//
Функция ПолучитьПисьмаПоИдентификаторам(Почта, ДанныеУчетнойЗаписи, ИдентификаторыПисемКЗагрузке, 
	ПолученныеПисьма, ВсеИдентификаторы = Неопределено)
	
	ПолученоПисем = 0;
	
	Если ИдентификаторыПисемКЗагрузке.Количество() <> 0 Тогда
		
		ОтветственныйЗаОбработкуПисем = ДанныеУчетнойЗаписи.ОтветственныйЗаОбработкуПисем;
		КоличествоОшибокПриЗаписи = 0;
		КоличествоНеАктуальныхСообщений = 0;
		
		Пока ИдентификаторыПисемКЗагрузке.Количество() > (ПолученоПисем + КоличествоОшибокПриЗаписи + КоличествоНеАктуальныхСообщений) Цикл
			
			КоличествоВПорции = 0;
			ИдентификаторыПорцииДляЗагрузки = Новый Массив;
			
			Для Индекс = (ПолученоПисем + КоличествоОшибокПриЗаписи) По ИдентификаторыПисемКЗагрузке.Количество() - 1 Цикл
				
				ИдентификаторыПорцииДляЗагрузки.Добавить(ИдентификаторыПисемКЗагрузке.Получить(Индекс));
				КоличествоВПорции = КоличествоВПорции + 1;
				Если КоличествоВПорции = 5 Тогда
					Прервать;
				КонецЕсли;
				
			КонецЦикла;
			
			Попытка
				Сообщения = Почта.Выбрать(Ложь, ИдентификаторыПорцииДляЗагрузки,
					?(ДанныеУчетнойЗаписи.ПротоколВходящейПочты = "IMAP", Ложь, Истина)); // Массив из ИнтернетПочтовоеСообщение
			Исключение
				ТекстОшибкиДляЖурналаРегистрации = РаботаСПочтовымиСообщениями.РасширенноеПредставлениеОшибки(
					ИнформацияОбОшибке(), ОбщегоНазначения.КодОсновногоЯзыка());
					
				ТекстОшибкиДляЖурналаРегистрации = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось подключиться к почте %1 по причине:
						|%2'", ОбщегоНазначения.КодОсновногоЯзыка()),
						ДанныеУчетнойЗаписи.Ссылка,
						ТекстОшибкиДляЖурналаРегистрации);
					
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(),
					УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибкиДляЖурналаРегистрации);
					
				ТекстОшибки = РаботаСПочтовымиСообщениями.РасширенноеПредставлениеОшибки(ИнформацияОбОшибке(), , Ложь);
				ВызватьИсключение ТекстОшибки;
			КонецПопытки;
			
			КоличествоНеАктуальныхСообщений = КоличествоНеАктуальныхСообщений + (КоличествоВПорции - Сообщения.Количество());
			
			Для Каждого Сообщение Из Сообщения Цикл
				
				ДобавлятьВМассивПисемДляПолученияПапки = Ложь;
				
				Блокировка = Новый БлокировкаДанных;
				Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
					ЭлементБлокировки = Блокировка.Добавить("Справочник.УчетныеЗаписиЭлектроннойПочты");
					ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
					ЭлементБлокировки = Блокировка.Добавить("Справочник.ПапкиЭлектронныхПисем");
					ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
					Блокировка.Добавить("РегистрСведений.ИдентификаторыПолученныхЭлектронныхПисем");
					Блокировка.Добавить("РегистрСведений.УведомленияОПрочтении");
					Блокировка.Добавить("Документ.ЭлектронноеПисьмоИсходящее");
					Блокировка.Добавить("Документ.ЭлектронноеПисьмоВходящее");
				КонецЕсли;
				
				НачатьТранзакцию();
				Попытка
					Блокировка.Заблокировать();
					
					ЭтоИсходящееПисьмо = ПочтовыеАдресаРавны(ДанныеУчетнойЗаписи.АдресЭлектроннойПочты,
						АдресОтправителяИнтернетПочтовогоСообщения(Сообщение.Отправитель));
					// @skip-check query-in-loop - По-объектная запись данных.
					СозданноеПисьмо = ЗаписатьЭлектронноеПисьмо(ДанныеУчетнойЗаписи, Сообщение, 
						ОтветственныйЗаОбработкуПисем, ДанныеУчетнойЗаписи.ПомещатьПисьмоВПапкуПисьмаОснования,
						ДобавлятьВМассивПисемДляПолученияПапки, ЭтоИсходящееПисьмо);
					
					ПолученоПисем = ПолученоПисем + 1;
					ЗафиксироватьТранзакцию();
					
				Исключение
					
					ОтменитьТранзакцию();
					ТекстСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Не удалось получить письмо %1 от %2, отправленное c адреса %3, по причине:
						|%4'", ОбщегоНазначения.КодОсновногоЯзыка()),
							Сообщение.Тема, Сообщение.ДатаОтправления, Сообщение.Отправитель.Адрес,
							ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
					ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка, , ,
						ТекстСообщенияОбОшибке);
					
					КоличествоОшибокПриЗаписи = КоличествоОшибокПриЗаписи + 1;
					
					Если ВсеИдентификаторы <> Неопределено Тогда
						Для Каждого ИдентификаторСообщения Из Сообщение.Идентификатор Цикл
							ИндексИдентификатораВМассиве = ВсеИдентификаторы.Найти(ИдентификаторСообщения);
							Если ИндексИдентификатораВМассиве <> Неопределено Тогда
								ВсеИдентификаторы.Удалить(ИндексИдентификатораВМассиве);
							КонецЕсли;
							Продолжить;
						КонецЦикла;
					КонецЕсли;
					
				КонецПопытки;
				
				ПолученныеПисьма.ВсеПолученныеПисьма.Добавить(СозданноеПисьмо);
				ПолученныеПисьма.ПолученныеПисьмаПоУчетнойЗаписи.Добавить(СозданноеПисьмо);
				Если ДобавлятьВМассивПисемДляПолученияПапки Тогда
					ПолученныеПисьма.ПисьмаДляОпределенияПапок.Добавить(СозданноеПисьмо);
				КонецЕсли;
				
			КонецЦикла;
		
		КонецЦикла;
		
	КонецЕсли;
	Возврат ПолученоПисем;
	
КонецФункции

Функция ДатаОтбораЗагрузкиПисемПоПротоколуIMAP(ДатаЗагрузкиПисем)
	
	Возврат Мин(ДатаЗагрузкиПисем, УниверсальноеВремя(ДатаЗагрузкиПисем, ЧасовойПояс())); 
	
КонецФункции

Процедура ОпределитьИдентификаторыВходящегоСообщения(ЗаголовокПисьма, ТаблицаИдентификаторов)
	
	СтрокаТаблицыИдентификаторов = ТаблицаИдентификаторов.Добавить();
	СтрокаТаблицыИдентификаторов.ИдентификаторНаСервере = ?(ЗаголовокПисьма.Идентификатор.Количество() = 0,
		"", 
		ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(ЗаголовокПисьма.Идентификатор[0], ""));
	СтрокаТаблицыИдентификаторов.ИдентификаторПисьма =
		ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(ЗаголовокПисьма.ИдентификаторСообщения, "");
	
	Если СтрНайти(НРег(ЗаголовокПисьма.ИдентификаторСообщения), "outlook.com") = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ПозицияIDОригинальногоСообщения = СтрНайти(ЗаголовокПисьма.Заголовок, "X-Microsoft-Original-Message-ID");
	Если ПозицияIDОригинальногоСообщения = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Начало = СтрНайти(ЗаголовокПисьма.Заголовок, "<", НаправлениеПоиска.СНачала, ПозицияIDОригинальногоСообщения);
	Конец = СтрНайти(ЗаголовокПисьма.Заголовок, ">", НаправлениеПоиска.СНачала, ПозицияIDОригинальногоСообщения);
	ОригинальныйIDСообщенияMicrosoft = Сред(ЗаголовокПисьма.Заголовок, Начало + 1, Конец - Начало - 1);	
	СтрокаТаблицыИдентификаторов.ИдентификаторОригинальногоПисьмаMicrosoft =
		ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(ОригинальныйIDСообщенияMicrosoft, "");
	
КонецПроцедуры

// Параметры:
//  ДанныеУчетнойЗаписи - ВыборкаИзРезультатаЗапроса
//  Почта - ИнтернетПочта
//  ПолученоПисем - Число
//  ПолученныеПисьма - см. ПолученныеПисьма
//
Процедура ПолучитьПочтуПоПроколуIMAP(ДанныеУчетнойЗаписи, Почта, ПолученоПисем, ПолученныеПисьма)
	
	ИменаАктивныхПапок = ИменаАктивныхПапок(Почта);
	
	КвалификаторСтроки255 =  Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(255,ДопустимаяДлина.Переменная));
	
	ТаблицаИдентификаторов = Новый ТаблицаЗначений;
	ТаблицаИдентификаторов.Колонки.Добавить("ИдентификаторНаСервере",                    КвалификаторСтроки255);
	ТаблицаИдентификаторов.Колонки.Добавить("ИдентификаторПисьма",                       КвалификаторСтроки255);
	ТаблицаИдентификаторов.Колонки.Добавить("ИдентификаторОригинальногоПисьмаMicrosoft", КвалификаторСтроки255);
	
	ТаблицаПустыхИдентификаторов  = Новый ТаблицаЗначений;
	ТаблицаПустыхИдентификаторов.Колонки.Добавить("ИдентификаторНаСервере", КвалификаторСтроки255);
	ТаблицаПустыхИдентификаторов.Колонки.Добавить("ХешСумма", ОбщегоНазначения.ОписаниеТипаСтрока(32));
	
	ДатаЗагрузкиПисем = ТекущаяДатаСеанса();
	
	Для каждого ИмяАктивнойПапки Из ИменаАктивныхПапок Цикл
			
		Попытка
			Почта.ТекущийПочтовыйЯщик = ИмяАктивнойПапки;
		Исключение
			Продолжить;
		КонецПопытки;
		
		ПараметрыОтбора = Новый Структура;		
		Если Не ДанныеУчетнойЗаписи.ДатаЗагрузкиПисем = Дата(1,1,1) Тогда 
			ПараметрыОтбора.Вставить("ПослеДатыОтправления", 
				ДатаОтбораЗагрузкиПисемПоПротоколуIMAP(ДанныеУчетнойЗаписи.ДатаЗагрузкиПисем));
		Иначе
			ПараметрыОтбора.Вставить("Удаленные", Ложь);
		КонецЕсли;
		
		Попытка
			ЗаголовкиПисемДляЗагрузки = Почта.ПолучитьЗаголовки(ПараметрыОтбора);
		Исключение
			Продолжить;
		КонецПопытки;
		
		ЗаголовкиСПустымИдентификатором = Новый Массив;
		ТаблицаИдентификаторов.Очистить();
		ТаблицаПустыхИдентификаторов.Очистить();
		
		Для Каждого ЗаголовокПисьма Из ЗаголовкиПисемДляЗагрузки Цикл
			Если ПустаяСтрока(ЗаголовокПисьма.ИдентификаторСообщения) Тогда
				ЗаголовкиСПустымИдентификатором.Добавить(ЗаголовокПисьма);
				Продолжить;
			КонецЕсли;
			ОпределитьИдентификаторыВходящегоСообщения(ЗаголовокПисьма, ТаблицаИдентификаторов);
		КонецЦикла;
		
		Если ЗаголовкиСПустымИдентификатором.Количество() > 0 Тогда
			Для Каждого ЗаголовокПисьма Из ЗаголовкиСПустымИдентификатором Цикл
				НоваяСтрока = ТаблицаПустыхИдентификаторов.Добавить();
				НоваяСтрока.ИдентификаторНаСервере = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(
					ЗаголовокПисьма.Идентификатор[0], "");
				НоваяСтрока.ХешСумма = ХешСуммаПочтовогоСообщения(ЗаголовокПисьма);
			КонецЦикла;
		КонецЕсли;

		Если ТаблицаИдентификаторов.Количество() > 0 Или ЗаголовкиСПустымИдентификатором.Количество() > 0 Тогда
		
			// АПК:96-выкл Ключевое слово ОБЪЕДИНИТЬ, т.к. двум запросам-условиям может соответствовать письмо с одним и тем же идентификатором.
			Запрос = Новый Запрос;
			Запрос.Текст = "
			|ВЫБРАТЬ
			|	ИдентификаторыПисемКЗагрузке.ИдентификаторПисьма                       КАК ИдентификаторПисьма,
			|	ИдентификаторыПисемКЗагрузке.ИдентификаторНаСервере                    КАК ИдентификаторНаСервере,
			|	ИдентификаторыПисемКЗагрузке.ИдентификаторОригинальногоПисьмаMicrosoft КАК ИдентификаторОригинальногоПисьмаMicrosoft
			|ПОМЕСТИТЬ ИдентификаторыПисемКЗагрузке
			|ИЗ
			|	&ИдентификаторыПисемКЗагрузке КАК ИдентификаторыПисемКЗагрузке
			|;
			|
			|////////////////////////////////////////////////////////////////////////////////
			|ВЫБРАТЬ
			|	ПустыеИдентификаторыПисемКЗагрузке.ХешСумма,
			|	ПустыеИдентификаторыПисемКЗагрузке.ИдентификаторНаСервере
			|ПОМЕСТИТЬ ПустыеИдентификаторыПисемКЗагрузке
			|ИЗ
			|	&ПустыеИдентификаторыПисемКЗагрузке КАК ПустыеИдентификаторыПисемКЗагрузке
			|;
			|
			|////////////////////////////////////////////////////////////////////////////////
			|ВЫБРАТЬ
			|	ИдентификаторыПисемКЗагрузке.ИдентификаторНаСервере КАК ИдентификаторНаСервере
			|ИЗ
			|	ИдентификаторыПисемКЗагрузке КАК ИдентификаторыПисемКЗагрузке
			|		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоВходящее КАК ЭлектронноеПисьмоВходящее
			|		ПО ИдентификаторыПисемКЗагрузке.ИдентификаторПисьма = ЭлектронноеПисьмоВходящее.ИдентификаторСообщения
			|			И (ЭлектронноеПисьмоВходящее.УчетнаяЗапись = &УчетнаяЗапись)
			|		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
			|		ПО (ЭлектронноеПисьмоИсходящее.УчетнаяЗапись = &УчетнаяЗапись)
			|			И (ИдентификаторыПисемКЗагрузке.ИдентификаторПисьма = ЭлектронноеПисьмоИсходящее.ИдентификаторСообщения
			|				ИЛИ ИдентификаторыПисемКЗагрузке.ИдентификаторПисьма = ЭлектронноеПисьмоИсходящее.ИдентификаторСообщенияОтправкаIMAP
			|				ИЛИ ИдентификаторыПисемКЗагрузке.ИдентификаторОригинальногоПисьмаMicrosoft = ЭлектронноеПисьмоИсходящее.ИдентификаторСообщения
			|					И ЭлектронноеПисьмоИсходящее.СтатусПисьма = ЗНАЧЕНИЕ(Перечисление.СтатусыИсходящегоЭлектронногоПисьма.Отправлено)
			|					И ЭлектронноеПисьмоИсходящее.ИдентификаторСообщения <> """")
			|ГДЕ
			|	ЭлектронноеПисьмоВходящее.Ссылка ЕСТЬ NULL
			|	И ЭлектронноеПисьмоИсходящее.Ссылка ЕСТЬ NULL
			|
			|ОБЪЕДИНИТЬ
			|
			|ВЫБРАТЬ
			|	ИдентификаторыПисемКЗагрузке.ИдентификаторНаСервере
			|ИЗ
			|	ПустыеИдентификаторыПисемКЗагрузке КАК ИдентификаторыПисемКЗагрузке
			|		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоВходящее КАК ЭлектронноеПисьмоВходящее
			|		ПО ИдентификаторыПисемКЗагрузке.ХешСумма = ЭлектронноеПисьмоВходящее.ХешСумма
			|			И (ЭлектронноеПисьмоВходящее.УчетнаяЗапись = &УчетнаяЗапись)
			|		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
			|		ПО (ЭлектронноеПисьмоИсходящее.УчетнаяЗапись = &УчетнаяЗапись)
			|			И (ИдентификаторыПисемКЗагрузке.ХешСумма = ЭлектронноеПисьмоИсходящее.ХешСумма)
			|ГДЕ
			|	ЭлектронноеПисьмоВходящее.Ссылка ЕСТЬ NULL
			|	И ЭлектронноеПисьмоИсходящее.Ссылка ЕСТЬ NULL";
			// АПК:96-вкл
			
			Запрос.УстановитьПараметр("ИдентификаторыПисемКЗагрузке", ТаблицаИдентификаторов);
			Запрос.УстановитьПараметр("ПустыеИдентификаторыПисемКЗагрузке", ТаблицаПустыхИдентификаторов);
			Запрос.УстановитьПараметр("УчетнаяЗапись", ДанныеУчетнойЗаписи.Ссылка);
			
			// @skip-check query-in-loop - Порционная загрузка писем из папок.
			ИдентификаторыПисемКЗагрузке = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("ИдентификаторНаСервере");
			ПолученоПисем = ПолученоПисем + ПолучитьПисьмаПоИдентификаторам(Почта, ДанныеУчетнойЗаписи, 
				ИдентификаторыПисемКЗагрузке, ПолученныеПисьма);
		
		КонецЕсли;
	КонецЦикла;
	
	УстановитьДатуПоследнейЗагрузкиПисем(ДанныеУчетнойЗаписи.Ссылка, ДатаЗагрузкиПисем);
	
КонецПроцедуры

Процедура ПолучитьПочтуПоПроколуPOP3(ДанныеУчетнойЗаписи, Почта, ПолученоПисем, ПолученныеПисьма)

	Идентификаторы = Почта.ПолучитьИдентификаторы();
	Если Идентификаторы.Количество() = 0 И (Не ДанныеУчетнойЗаписи.ОставлятьКопии) Тогда
		// Если на сервере сообщений нет, то удалим все записи по учетной записи в регистре сведений
		// ИдентификаторыПолученныхЭлектронныхПисем.
		УдалитьИдентификаторыВсехРанееПолученныхПисем(ДанныеУчетнойЗаписи.Ссылка);
		Возврат;
	КонецЕсли;

	// Определим какие сообщения нужно получать.
	ИдентификаторыПисемКЗагрузке = ПолучитьИдентификаторыПисемДляЗагрузки(Идентификаторы, ДанныеУчетнойЗаписи.Ссылка);
	ПолученоПисем = ПолученоПисем + ПолучитьПисьмаПоИдентификаторам(Почта, ДанныеУчетнойЗаписи,
		ИдентификаторыПисемКЗагрузке, ПолученныеПисьма, Идентификаторы);
	
	// Удалим ненужные сообщения на сервере.
	УдалятьВсе = Не ДанныеУчетнойЗаписи.ОставлятьКопии;
	Если УдалятьВсе Тогда
		УдаляемыеСообщения = Идентификаторы;
	Иначе
		Если ДанныеУчетнойЗаписи.ОставлятьДней > 0 Тогда
			УдаляемыеСообщения = ПолучитьИдентификаторыПисемДляУдаленияНаСервере(Идентификаторы, 
				ДанныеУчетнойЗаписи.Ссылка, 
				ТекущаяДатаСеанса() - ДанныеУчетнойЗаписи.ОставлятьДней * 24 * 60 * 60);
		Иначе
			УдаляемыеСообщения = Новый Массив;
		КонецЕсли;
	КонецЕсли;
	
	Если УдаляемыеСообщения.Количество() <> 0 Тогда
		Почта.УдалитьСообщения(УдаляемыеСообщения);
	КонецЕсли;
	
	Если УдалятьВсе Тогда
		УдалитьИдентификаторыВсехРанееПолученныхПисем(ДанныеУчетнойЗаписи.Ссылка);
	Иначе
		УдалитьИдентификаторыРанееПолученныхПисем(ДанныеУчетнойЗаписи.Ссылка, Идентификаторы, УдаляемыеСообщения);
	КонецЕсли;

КонецПроцедуры

Функция ПочтовыеАдресаРавны(ПервыйАдрес, ВторойАдрес)

	ОбработанныйПервыйАдрес = НРег(СокрЛП(ПервыйАдрес));
	ОбработанныйВторойАдрес = НРег(СокрЛП(ВторойАдрес));
	
	ИзменитьДоменВПочтовомАдресеЕслиНеобходимо(ОбработанныйПервыйАдрес);
	ИзменитьДоменВПочтовомАдресеЕслиНеобходимо(ОбработанныйВторойАдрес);
	
	Возврат (ОбработанныйПервыйАдрес = ОбработанныйВторойАдрес);
	
КонецФункции

Функция СтруктураАдресаЭлектроннойПочты(АдресЭлектроннойПочты)
	
	МассивАдреса = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(АдресЭлектроннойПочты,"@");
	
	Если МассивАдреса.Количество() = 2 Тогда
		
		СтруктураАдреса = Новый Структура;
		СтруктураАдреса.Вставить("ИмяПочтовогоЯщика", МассивАдреса[0]);
		СтруктураАдреса.Вставить("Домен"            , МассивАдреса[1]);
		
		Возврат СтруктураАдреса;
	Иначе
		Возврат Неопределено;
	КонецЕсли;
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * ВсеПолученныеПисьма - Массив из ДокументСсылка.ЭлектронноеПисьмоВходящее
//                         - Массив из ДокументСсылка.ЭлектронноеПисьмоИсходящее
//   * ПисьмаДляОпределенияПапок - Массив из ДокументСсылка.ЭлектронноеПисьмоВходящее
//                               - Массив из ДокументСсылка.ЭлектронноеПисьмоИсходящее
//   * ПолученныеПисьмаПоУчетнойЗаписи - Массив из ДокументСсылка.ЭлектронноеПисьмоВходящее
//                                     - Массив из ДокументСсылка.ЭлектронноеПисьмоИсходящее
//
Функция ПолученныеПисьма()
	
	Результат = Новый Структура;
	Результат.Вставить("ВсеПолученныеПисьма",             Новый Массив);
	Результат.Вставить("ПисьмаДляОпределенияПапок",       Новый Массив);
	Результат.Вставить("ПолученныеПисьмаПоУчетнойЗаписи", Новый Массив);
	Возврат Результат;
	
КонецФункции

Процедура УстановитьДатуПоследнейЗагрузкиПисем(УчетнаяЗапись, ДатаЗагрузки)

	МенеджерЗаписи = РегистрыСведений.ДатыПоследнейЗагрузкиПочтовыхСообщений.СоздатьМенеджерЗаписи();
	МенеджерЗаписи.УчетнаяЗапись     = УчетнаяЗапись;
	МенеджерЗаписи.ДатаЗагрузкиПисем = ДатаЗагрузки;
	МенеджерЗаписи.Записать();

КонецПроцедуры

Процедура СинхронизироватьПризнакРассмотреноССервером(Почта, ДанныеУчетнойЗаписи, МассивЗагруженныхПисем)

	Если НЕ ДанныеУчетнойЗаписи.ОбработкаПисемВедетсяВДругомПочтовомКлиенте Тогда
		Возврат;
	КонецЕсли;
	
	МассивИменАктивныхПапок = ИменаАктивныхПапок(Почта);
	
	МассивИдентификаторовНеПрочитанныхПисем = Новый Массив;
	
	Для каждого ИмяАктивнойПапки Из МассивИменАктивныхПапок Цикл
			
		Попытка
			Почта.ТекущийПочтовыйЯщик = ИмяАктивнойПапки;
		Исключение
			Продолжить;
		КонецПопытки;
		
		ПараметрыОтбора = Новый Структура;
		ПараметрыОтбора.Вставить("Прочитанные", Ложь);
		
		Попытка
			ЗаголовкиПрочитанныхПисем = Почта.ПолучитьЗаголовки(ПараметрыОтбора);
		Исключение
			Продолжить;
		КонецПопытки;
		
		
		Для Каждого ЗаголовокПисьма Из ЗаголовкиПрочитанныхПисем Цикл
			
			МассивИдентификаторовНеПрочитанныхПисем.Добавить(ЗаголовокПисьма.ИдентификаторСообщения);
			
		КонецЦикла;
			
	КонецЦикла;
	
	ТаблицаИдентификаторов = Новый ТаблицаЗначений;
	ТаблицаИдентификаторов.Колонки.Добавить("Идентификатор", 
	                                        Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(150,ДопустимаяДлина.Переменная)));
	
	ОбщегоНазначенияКлиентСервер.ДополнитьТаблицуИзМассива(ТаблицаИдентификаторов,
	                                                       МассивИдентификаторовНеПрочитанныхПисем,
	                                                       "Идентификатор");
	
	Запрос = Новый Запрос;
	Запрос.Текст = "
	|ВЫБРАТЬ
	|	ИдентификаторыПрочтенныхПисем.Идентификатор
	|ПОМЕСТИТЬ ИдентификаторыПрочтенныхПисем
	|ИЗ
	|	&ИдентификаторыПрочтенныхПисем КАК ИдентификаторыПрочтенныхПисем
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	Взаимодействия.Ссылка КАК Ссылка,
	|	ЛОЖЬ КАК Рассмотрено
	|ИЗ
	|	ИдентификаторыПрочтенныхПисем КАК ИдентификаторыПрочтенныхПисем
	|		ЛЕВОЕ СОЕДИНЕНИЕ ЖурналДокументов.Взаимодействия КАК Взаимодействия
	|		ПО ИдентификаторыПрочтенныхПисем.Идентификатор = Взаимодействия.ИдентификаторСообщения
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействий
	|		ПО (Взаимодействия.Ссылка = ПредметыПапкиВзаимодействий.Взаимодействие)
	|ГДЕ
	|	Взаимодействия.УчетнаяЗапись = &УчетнаяЗапись
	|	И ЕСТЬNULL(ПредметыПапкиВзаимодействий.Рассмотрено, ЛОЖЬ) = ИСТИНА
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	Взаимодействия.Ссылка,
	|	ИСТИНА
	|ИЗ
	|	ЖурналДокументов.Взаимодействия КАК Взаимодействия
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействий
	|		ПО Взаимодействия.Ссылка = ПредметыПапкиВзаимодействий.Взаимодействие
	|		ЛЕВОЕ СОЕДИНЕНИЕ ИдентификаторыПрочтенныхПисем КАК ИдентификаторыПрочтенныхПисем
	|		ПО ИдентификаторыПрочтенныхПисем.Идентификатор = Взаимодействия.ИдентификаторСообщения
	|ГДЕ
	|	ЕСТЬNULL(ПредметыПапкиВзаимодействий.Рассмотрено, ЛОЖЬ) = ЛОЖЬ
	|	И Взаимодействия.УчетнаяЗапись = &УчетнаяЗапись
	|	И ИдентификаторыПрочтенныхПисем.Идентификатор IS NULL";
	
	Запрос.УстановитьПараметр("ИдентификаторыПрочтенныхПисем", ТаблицаИдентификаторов);
	Запрос.УстановитьПараметр("УчетнаяЗапись", ДанныеУчетнойЗаписи.Ссылка);
	
	Результат = Запрос.Выполнить();
	Если Результат.Пустой() Тогда
		Возврат;
	КонецЕсли;
	
	МассивПисемРассмотрено   = Новый Массив;
	МассивПисемНеРассмотрено = Новый Массив;
	
	Выборка = Результат.Выбрать();
	
	НачатьТранзакцию();
	Попытка
		
		ТаблицаОбластиБлокировки = Новый ТаблицаЗначений;
		ТаблицаОбластиБлокировки.Колонки.Добавить("Взаимодействие");
		
		Пока Выборка.Следующий() Цикл
			Если Выборка.Рассмотрено Тогда
				МассивПисемРассмотрено.Добавить(Выборка.Ссылка);
			Иначе
				МассивПисемНеРассмотрено.Добавить(Выборка.Ссылка);
			КонецЕсли;
			НоваяСтрока = ТаблицаОбластиБлокировки.Добавить();
			НоваяСтрока.Взаимодействие = Выборка.Ссылка;
		КонецЦикла;
		
		Блокировка = Новый БлокировкаДанных;
		
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПредметыПапкиВзаимодействий");
		ЭлементБлокировки.ИсточникДанных = ТаблицаОбластиБлокировки;
		Блокировка.Заблокировать();
	
		ЕстьИзменения = Ложь;
		
		Взаимодействия.УстановитьПризнакРассмотрено(МассивПисемРассмотрено, Истина, ЕстьИзменения);
		Взаимодействия.УстановитьПризнакРассмотрено(МассивПисемНеРассмотрено, Ложь, ЕстьИзменения);
		
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивЗагруженныхПисем, МассивПисемРассмотрено, Ложь);
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивЗагруженныхПисем, МассивПисемНеРассмотрено, Ложь);
		
		ЗафиксироватьТранзакцию();
	
	Исключение
		
		ОтменитьТранзакцию();
		ТекстСообщения = НСтр("ru = 'Не удалось изменить информацию о признаке рассмотрено для писем по причине : %Причина%.'");
		ТекстСообщения = СтрЗаменить(ТекстСообщения, "%Причина%", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			УровеньЖурналаРегистрации.Ошибка,
			Метаданные.РегистрыСведений.ПредметыПапкиВзаимодействий,
			,
			ТекстСообщения);
		
	КонецПопытки;
	
КонецПроцедуры

Процедура УдалитьИдентификаторыВсехРанееПолученныхПисем(УчетнаяЗапись)
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных();
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ИдентификаторыПолученныхЭлектронныхПисем");
		ЭлементБлокировки.УстановитьЗначение("УчетнаяЗапись", УчетнаяЗапись);
		Блокировка.Заблокировать();
		
		Запрос = Новый Запрос;
		Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ИдентификаторыПолученныхЭлектронныхПисем.Идентификатор
		|ИЗ
		|	РегистрСведений.ИдентификаторыПолученныхЭлектронныхПисем КАК ИдентификаторыПолученныхЭлектронныхПисем
		|ГДЕ
		|	ИдентификаторыПолученныхЭлектронныхПисем.УчетнаяЗапись = &УчетнаяЗапись";
		Запрос.УстановитьПараметр("УчетнаяЗапись", УчетнаяЗапись);
		
		Если НЕ Запрос.Выполнить().Пустой() Тогда
			Набор = РегистрыСведений.ИдентификаторыПолученныхЭлектронныхПисем.СоздатьНаборЗаписей();
			Набор.Отбор.УчетнаяЗапись.Установить(УчетнаяЗапись);
			Набор.Записать();
		КонецЕсли;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Процедура УдалитьИдентификаторыРанееПолученныхПисем(УчетнаяЗапись, ИдентификаторыНаСервере, ИдентификаторыУдалять)
	
	// Получим список идентификаторов которые не нужно удалять.
	ИдентификаторыКУдалению = Новый Соответствие;
	Для Каждого Элемент Из ИдентификаторыУдалять Цикл
		ИдентификаторыКУдалению.Вставить(Элемент, Истина);
	КонецЦикла;
	
	ИдентификаторыОставляем = Новый Массив;
	Для Каждого Элемент Из ИдентификаторыНаСервере Цикл
		Если ИдентификаторыКУдалению.Получить(Элемент) = Неопределено Тогда
			ИдентификаторыОставляем.Добавить(Элемент);
		КонецЕсли;
	КонецЦикла;
	
	// Получим идентификаторы которые нужно удалить, те которые есть в регистре, но не нужно оставлять.
	ТаблицаИдентификаторов = СоздатьТаблицуСИдентификаторами(ИдентификаторыОставляем);

	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ТаблицаИдентификаторов", ТаблицаИдентификаторов);
	Запрос.УстановитьПараметр("УчетнаяЗапись", УчетнаяЗапись);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ТаблицаИдентификаторов.Идентификатор
	|ПОМЕСТИТЬ ТаблицаИдентификаторов
	|ИЗ
	|	&ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	&УчетнаяЗапись                                         КАК УчетнаяЗапись,
	|	ИдентификаторыПолученныхЭлектронныхПисем.Идентификатор КАК Идентификатор
	|ИЗ
	|	РегистрСведений.ИдентификаторыПолученныхЭлектронныхПисем КАК ИдентификаторыПолученныхЭлектронныхПисем
	|		ЛЕВОЕ СОЕДИНЕНИЕ ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|		ПО ТаблицаИдентификаторов.Идентификатор = ИдентификаторыПолученныхЭлектронныхПисем.Идентификатор
	|ГДЕ
	|	ТаблицаИдентификаторов.Идентификатор ЕСТЬ NULL
	|	 И ИдентификаторыПолученныхЭлектронныхПисем.УчетнаяЗапись = &УчетнаяЗапись";
	
	ТаблицаУдаляемыхИдентификаторов = Запрос.Выполнить().Выгрузить();
	
	НачатьТранзакцию();
	Попытка
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ИдентификаторыПолученныхЭлектронныхПисем");
		ЭлементБлокировки.ИсточникДанных = ТаблицаУдаляемыхИдентификаторов;
		Блокировка.Заблокировать();
		
		Для Каждого СтрокаТаблицы Из ТаблицаУдаляемыхИдентификаторов Цикл
			Набор = РегистрыСведений.ИдентификаторыПолученныхЭлектронныхПисем.СоздатьНаборЗаписей();
			Набор.Отбор.УчетнаяЗапись.Установить(СтрокаТаблицы["УчетнаяЗапись"]);
			Набор.Отбор.Идентификатор.Установить(СтрокаТаблицы["Идентификатор"]);
			Набор.Записать();
		КонецЦикла;
		
		ЗафиксироватьТранзакцию();
	
	Исключение
		
		ОтменитьТранзакцию();
		ТекстСообщения = НСтр("ru = 'Не удалось очистить информацию о ранее полученных идентификаторах по причине: %Причина%.'");
		ТекстСообщения = СтрЗаменить(ТекстСообщения, "%Причина%", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			УровеньЖурналаРегистрации.Ошибка,
			Метаданные.РегистрыСведений.ИдентификаторыПолученныхЭлектронныхПисем,
			СтрокаТаблицы.УчетнаяЗапись,
			ТекстСообщения);
	
	КонецПопытки;
	
КонецПроцедуры

Функция СоздатьТаблицуСИдентификаторами(Идентификаторы)
	
	ТаблицаИдентификаторов = Новый ТаблицаЗначений;
	ТаблицаИдентификаторов.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка",,, Новый КвалификаторыСтроки(100)));
	Для Каждого Идентификатор Из Идентификаторы Цикл
		НоваяСтрока = ТаблицаИдентификаторов.Добавить();
		НоваяСтрока.Идентификатор = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Идентификатор, "");
	КонецЦикла;
	
	Возврат ТаблицаИдентификаторов;
	
КонецФункции

Функция ПолучитьИдентификаторыПисемДляЗагрузки(Идентификаторы, УчетнаяЗапись)

	// Получим список сообщений которые не были раньше получены.
	ТаблицаИдентификаторов = СоздатьТаблицуСИдентификаторами(Идентификаторы);

	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ТаблицаИдентификаторов", ТаблицаИдентификаторов);
	Запрос.УстановитьПараметр("УчетнаяЗапись",          УчетнаяЗапись);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ТаблицаИдентификаторов.Идентификатор
	|ПОМЕСТИТЬ ТаблицаИдентификаторов
	|ИЗ
	|	&ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ТаблицаИдентификаторов.Идентификатор
	|ИЗ
	|	ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ИдентификаторыПолученныхЭлектронныхПисем КАК ИдентификаторыПолученныхЭлектронныхПисем
	|		ПО ТаблицаИдентификаторов.Идентификатор = ИдентификаторыПолученныхЭлектронныхПисем.Идентификатор
	|			И (ИдентификаторыПолученныхЭлектронныхПисем.УчетнаяЗапись = &УчетнаяЗапись)
	|ГДЕ
	|	ИдентификаторыПолученныхЭлектронныхПисем.УчетнаяЗапись ЕСТЬ NULL ";

	Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Идентификатор");

КонецФункции

Функция ПолучитьИдентификаторыПисемДляУдаленияНаСервере(Идентификаторы, УчетнаяЗапись, ДатаПоКоторуюУдалять)

	ТаблицаИдентификаторов = СоздатьТаблицуСИдентификаторами(Идентификаторы);

	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ТаблицаИдентификаторов", ТаблицаИдентификаторов);
	Запрос.УстановитьПараметр("УчетнаяЗапись", УчетнаяЗапись);
	Запрос.УстановитьПараметр("ДатаПолучения", ДатаПоКоторуюУдалять);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ТаблицаИдентификаторов.Идентификатор
	|ПОМЕСТИТЬ ТаблицаИдентификаторов
	|ИЗ
	|	&ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ТаблицаИдентификаторов.Идентификатор
	|ИЗ
	|	ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ИдентификаторыПолученныхЭлектронныхПисем КАК ИдентификаторыПолученныхЭлектронныхПисем
	|		ПО ТаблицаИдентификаторов.Идентификатор = ИдентификаторыПолученныхЭлектронныхПисем.Идентификатор
	|			И (ИдентификаторыПолученныхЭлектронныхПисем.УчетнаяЗапись = &УчетнаяЗапись)
	|ГДЕ
	|	ИдентификаторыПолученныхЭлектронныхПисем.ДатаПолучения <= &ДатаПолучения";

	Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Идентификатор");

КонецФункции

Функция ЗаписатьЭлектронноеПисьмо(ДанныеУчетнойЗаписи, Сообщение, ОтветственныйЗаОбработкуПисем,
	ПомещатьПисьмоВПапкуПисьмаОснования, ДобавлятьВМассивПисемДляПолученияПапки, ЭтоИсходящееПисьмо);
	
	НачатьТранзакцию();
	Попытка
		Если ЭтоИсходящееПисьмо Тогда
			Письмо = Документы.ЭлектронноеПисьмоИсходящее.СоздатьДокумент();
		Иначе
			Письмо = Документы.ЭлектронноеПисьмоВходящее.СоздатьДокумент();
		КонецЕсли;
			
		ЗаполнитьДокументЭлектронноеПисьмо(Письмо, Сообщение, ЭтоИсходящееПисьмо);
		Письмо.УчетнаяЗапись = ДанныеУчетнойЗаписи.Ссылка;
		ПредметИПапка = ПредметИПапкаЗагружаемогоПисьма(Письмо, ДанныеУчетнойЗаписи.Ссылка,
		                                                ЭтоИсходящееПисьмо, ПомещатьПисьмоВПапкуПисьмаОснования);
		ЗаполнитьКонтактыВЗагружаемомПисьме(Письмо, ЭтоИсходящееПисьмо);
		Письмо.Ответственный = ОтветственныйЗаОбработкуПисем;
		Письмо.Записать();
	
		Если ДанныеУчетнойЗаписи.ОбработкаПисемВедетсяВДругомПочтовомКлиенте Тогда 
			ПризнакРассмотрено = Истина;
		Иначе
			ПризнакРассмотрено = ?(ЭтоИсходящееПисьмо, Истина, Ложь);
		КонецЕсли;
		
		Реквизиты = РегистрыСведений.ПредметыПапкиВзаимодействий.РеквизитыВзаимодействия();
		Реквизиты.Папка                   = ПредметИПапка.Папка;
		Реквизиты.Предмет                 = ПредметИПапка.Предмет;
		Реквизиты.Рассмотрено             = ПризнакРассмотрено;
		Реквизиты.РассчитыватьРассмотрено = Ложь;
		РегистрыСведений.ПредметыПапкиВзаимодействий.ЗаписатьПредметыПапкиВзаимодействий(Письмо.Ссылка, Реквизиты);
		
		Если Не ДанныеУчетнойЗаписи.ПротоколВходящейПочты = "IMAP" Тогда
			ЗаписатьИдентификаторПолученногоПисьма(ДанныеУчетнойЗаписи.Ссылка, Письмо.ИдентификаторНаСервере,
				Сообщение.ДатаПолучения);
		КонецЕсли;
		
		Если Не ЭтоИсходящееПисьмо И Письмо.УведомитьОПрочтении Тогда
			ЗаписатьНеобходимостьОбработкиУведомленияОПрочтении(Письмо.Ссылка);
		КонецЕсли;
	
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	// Запишем вложения вне транзакции записи письма
	УникальныеИменаВложений = Новый Соответствие;
	Для Каждого Вложение Из Сообщение.Вложения Цикл
		УникальныеИменаВложений[Вложение.ИмяФайла] = ?(УникальныеИменаВложений[Вложение.ИмяФайла] = Неопределено,
			Истина, Ложь);
	КонецЦикла;
	
	ИменаВложений = Новый Массив;
	Для Каждого Вложение Из Сообщение.Вложения Цикл
		Если УникальныеИменаВложений[Вложение.ИмяФайла] = Истина Тогда 
			ИменаВложений.Добавить(Вложение.ИмяФайла);
		КонецЕсли;
	КонецЦикла;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		МодульЭлектроннаяПодписьСлужебный = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьСлужебный");
		СоответствиеВложенийИПодписей =
			МодульЭлектроннаяПодписьСлужебный.ИменаФайловПодписейИменФайловДанных(ИменаВложений);
	Иначе
		СоответствиеВложенийИПодписей = Новый Соответствие;
		Для Каждого ИмяФайлаВложения Из ИменаВложений Цикл
			СоответствиеВложенийИПодписей.Вставить(ИмяФайлаВложения, Новый Массив);
		КонецЦикла;
	КонецЕсли;
	
	КоличествоПустыхИменВоВложениях = 0;
	Для каждого ЭлементСоответствия Из СоответствиеВложенийИПодписей Цикл
		
		НайденноеВложение = Неопределено;
		МассивПодписей    = Новый Массив;
		
		Для каждого Вложение Из Сообщение.Вложения Цикл
			Если Вложение.ИмяФайла = ЭлементСоответствия.Ключ Тогда
				НайденноеВложение = Вложение;
				Прервать;
			КонецЕсли
		КонецЦикла;
		
		Если НайденноеВложение <> Неопределено И ЭлементСоответствия.Значение.Количество() > 0 Тогда
			Для каждого Вложение Из Сообщение.Вложения Цикл
				Если ЭлементСоответствия.Значение.Найти(Вложение.ИмяФайла) <> Неопределено Тогда
					МассивПодписей.Добавить(Вложение);
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		
		Если НайденноеВложение <> Неопределено Тогда
			ЗаписатьВложениеЭлектронногоПисьма(Письмо, НайденноеВложение, МассивПодписей, КоличествоПустыхИменВоВложениях);
		КонецЕсли;
		
	КонецЦикла;
	
	Для каждого Вложение Из Сообщение.Вложения Цикл
		Если УникальныеИменаВложений[Вложение.ИмяФайла] = Ложь Тогда // дублирующиеся имена вложений
			ЗаписатьВложениеЭлектронногоПисьма(Письмо, Вложение, Новый Массив, КоличествоПустыхИменВоВложениях);
		КонецЕсли;
	КонецЦикла;
	
	Если (Не ПомещатьПисьмоВПапкуПисьмаОснования) ИЛИ Не ЗначениеЗаполнено(ПредметИПапка.Папка) Тогда
		ДобавлятьВМассивПисемДляПолученияПапки = Истина;
	КонецЕсли;
	
	Возврат Письмо.Ссылка;
	
КонецФункции

// Заполняет документ электронное письмо по данным интернет-почтового сообщения.
// 
// Параметры:
//  Письмо             - ДокументОбъект.ЭлектронноеПисьмоВходящее
//                     - ДокументОбъект.ЭлектронноеПисьмоИсходящее -
//                       создаваемое письмо.
//  Сообщение          - ИнтернетПочтовоеСообщение - полученное сообщение.
//  ЭтоИсходящееПисьмо - Булево - признак того, что это письмо входящее.
//
Процедура ЗаполнитьДокументЭлектронноеПисьмо(Письмо, Сообщение, ЭтоИсходящееПисьмо)
	
	ОтправительАдрес = АдресОтправителяИнтернетПочтовогоСообщения(Сообщение.Отправитель);
	
	Если Не ЭтоИсходящееПисьмо Тогда
		Письмо.ДатаПолучения    = Сообщение.ДатаПолучения;
		Письмо.ОтправительАдрес = ОтправительАдрес; 
	Иначе
		Письмо.СтатусПисьма = Перечисления.СтатусыИсходящегоЭлектронногоПисьма.Отправлено;
		Письмо.ДатаОтправления = Сообщение.ДатаОтправления;
	КонецЕсли;
	
	ИмяОтправителя = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Сообщение.ИмяОтправителя, "");
	Письмо.ОтправительПредставление = ?(ПустаяСтрока(Сообщение.ИмяОтправителя),
		ОтправительАдрес,
		ИмяОтправителя + " <"+ ОтправительАдрес +">");
	
	Письмо.Важность = ПолучитьВажностьЭлектронногоПисьма(Сообщение.Важность);
	Письмо.Дата = ?(Сообщение.ДатаОтправления = Дата(1,1,1), ТекущаяДатаСеанса(), Сообщение.ДатаОтправления);
	Письмо.ВнутреннийЗаголовок = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Сообщение.Заголовок, "");
	Письмо.ИдентификаторНаСервере = ?(Сообщение.Идентификатор.Количество() = 0, "", 
		ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Сообщение.Идентификатор[0], ""));
	Письмо.ИдентификаторСообщения = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Сообщение.ИдентификаторСообщения, "");
	Письмо.Кодировка = Сообщение.Кодировка;
	Письмо.УведомитьОДоставке = Сообщение.УведомитьОДоставке;
	Письмо.УведомитьОПрочтении = Сообщение.УведомитьОПрочтении;
	
	Письмо.Размер = Сообщение.Размер;
	Письмо.Тема = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Сообщение.Тема);
	
	УстановитьТекстПисьма(Письмо, Сообщение);

	РаботаСПочтовымиСообщениямиСлужебный.ДекодироватьАдресаВПисьме(Сообщение);
	
	ЗаполнитьИнтернетПочтовыеАдреса(Письмо.ПолучателиКопий, Сообщение.Копии);
	ЗаполнитьИнтернетПочтовыеАдреса(Письмо.ПолучателиОтвета, Сообщение.ОбратныйАдрес);
	ЗаполнитьИнтернетПочтовыеАдреса(Письмо.ПолучателиПисьма, Сообщение.Получатели);
	
	Если ЭтоИсходящееПисьмо Тогда
		ЗаполнитьИнтернетПочтовыеАдреса(Письмо.ПолучателиСкрытыхКопий, Сообщение.СлепыеКопии);
	Иначе
		ЗаполнитьИнтернетПочтовыеАдреса(Письмо.АдресаУведомленияОПрочтении, Сообщение.АдресаУведомленияОПрочтении);
	КонецЕсли;
	
	Письмо.ИдентификаторОснования    = ИзПисьмаПолучитьИдентификаторОснования(Сообщение);
	Письмо.ИдентификаторыОснований   = Сообщение.ПолучитьПолеЗаголовка("References", "Строка");
	Письмо.ХешСумма                  = ХешСуммаПочтовогоСообщения(Сообщение);
	
	Для Каждого Вложение Из Сообщение.Вложения Цикл
		Если ПустаяСтрока(Вложение.Идентификатор) Или СтрНайти(Письмо.ТекстHTML, Вложение.Идентификатор) = 0 Тогда
			Письмо.ЕстьВложения = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ХешСуммаПочтовогоСообщения(Сообщение)
	
	Возврат ОбщегоНазначения.КонтрольнаяСуммаСтрокой(СокрЛП(Сообщение.Заголовок), ХешФункция.CRC32);
	
КонецФункции

Функция ПредметИПапкаЗагружаемогоПисьма(Письмо, УчетнаяЗапись, ЭтоИсходящееПисьмо, ПомещатьПисьмоВПапкуПисьмаОснования)
	
	Результат = Новый Структура("Предмет,Папка", Письмо.Ссылка, Неопределено);
	
	// Получим идентификаторы писем оснований.
	МассивИдентификаторов = Новый Массив;
	СтрокаИдентификаторы = Письмо.ИдентификаторыОснований;
	Пока Не ПустаяСтрока(СтрокаИдентификаторы) Цикл
		Позиция = СтрНайти(СтрокаИдентификаторы, "<");
		Если Позиция = 0 Тогда
			Прервать;
		КонецЕсли;
		СтрокаИдентификаторы = Сред(СтрокаИдентификаторы, Позиция+1);
		
		Позиция = СтрНайти(СтрокаИдентификаторы, ">");
		Если Позиция = 0 Тогда
			Прервать;
		КонецЕсли;
		
		ТекущийИдентификатор = СокрЛП(Лев(СтрокаИдентификаторы, Позиция-1));
		СтрокаИдентификаторы = СокрЛП(Сред(СтрокаИдентификаторы, Позиция+1));
		
		Если Не ПустаяСтрока(ТекущийИдентификатор) Тогда
			МассивИдентификаторов.Добавить(ТекущийИдентификатор);
		КонецЕсли;
	КонецЦикла;
	
	Если (МассивИдентификаторов.Найти(Письмо.ИдентификаторОснования) = Неопределено) 
		И (НЕ ПустаяСтрока(Письмо.ИдентификаторОснования)) Тогда
		МассивИдентификаторов.Добавить(Письмо.ИдентификаторОснования);
	КонецЕсли;
	
	Если МассивИдентификаторов.Найти(Письмо.ИдентификаторСообщения) = Неопределено 
		И НЕ ПустаяСтрока(Письмо.ИдентификаторСообщения) Тогда
		МассивИдентификаторов.Добавить(Письмо.ИдентификаторСообщения);
	КонецЕсли; 
	
	Если МассивИдентификаторов.Количество() = 0 Тогда
		Возврат Результат;
	КонецЕсли;
	
	ТаблицаИдентификаторов = СоздатьТаблицуСИдентификаторами(МассивИдентификаторов);
	
	// Получим все основания
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ТаблицаИдентификаторов.Идентификатор
	|ПОМЕСТИТЬ ТаблицаИдентификаторов
	|ИЗ
	|	&ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|ИНДЕКСИРОВАТЬ ПО
	|	Идентификатор
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоВходящее.Ссылка КАК Ссылка,
	|	ЭлектронноеПисьмоВходящее.Дата   КАК Дата,
	|	0                                КАК Приоритет
	|ПОМЕСТИТЬ ВсеЭлектронныеПисьма
	|ИЗ
	|	ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоВходящее КАК ЭлектронноеПисьмоВходящее
	|		ПО ТаблицаИдентификаторов.Идентификатор = ЭлектронноеПисьмоВходящее.ИдентификаторСообщения
	|ГДЕ
	|	ЭлектронноеПисьмоВходящее.УчетнаяЗапись = &УчетнаяЗапись
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоИсходящее.Ссылка КАК Ссылка,
	|	ЭлектронноеПисьмоИсходящее.Дата   КАК Дата,
	|	0                                 КАК Приоритет
	|ИЗ
	|	ТаблицаИдентификаторов КАК ТаблицаИдентификаторов
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
	|		ПО ТаблицаИдентификаторов.Идентификатор = ЭлектронноеПисьмоИсходящее.ИдентификаторСообщения
	|ГДЕ
	|	ЭлектронноеПисьмоИсходящее.УчетнаяЗапись = &УчетнаяЗапись
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоВходящее.Ссылка КАК Ссылка,
	|	ЭлектронноеПисьмоВходящее.Дата   КАК Дата,
	|	1                                КАК Приоритет
	|ИЗ
	|	Документ.ЭлектронноеПисьмоВходящее КАК ЭлектронноеПисьмоВходящее
	|ГДЕ
	|	ЭлектронноеПисьмоВходящее.УчетнаяЗапись = &УчетнаяЗапись
	|	И ЭлектронноеПисьмоВходящее.ИдентификаторОснования = &ИдентификаторСообщения
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоИсходящее.Ссылка КАК Ссылка,
	|	ЭлектронноеПисьмоИсходящее.Дата   КАК Дата,
	|	1                                 КАК Приоритет
	|ИЗ
	|	Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
	|ГДЕ
	|	ЭлектронноеПисьмоИсходящее.УчетнаяЗапись = &УчетнаяЗапись
	|	И ЭлектронноеПисьмоИсходящее.ИдентификаторОснования = &ИдентификаторСообщения
	|
	|ИНДЕКСИРОВАТЬ ПО
	|Ссылка
	|
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ ПЕРВЫЕ 1
	|	ВсеЭлектронныеПисьма.Ссылка,
	|	ВсеЭлектронныеПисьма.Приоритет,
	|	ВсеЭлектронныеПисьма.Дата КАК Дата,
	|	ЕСТЬNULL(ПредметыПапкиВзаимодействий.Предмет, НЕОПРЕДЕЛЕНО) КАК Предмет,
	|	ЕСТЬNULL(ПредметыПапкиВзаимодействий.ПапкаЭлектронногоПисьма, ЗНАЧЕНИЕ(Справочник.ПапкиЭлектронныхПисем.ПустаяСсылка)) КАК Папка,
	|	ЕСТЬNULL(ПапкиЭлектронныхПисем.ПредопределеннаяПапка, ЛОЖЬ) КАК ПредопределеннаяПапка
	|ИЗ
	|	ВсеЭлектронныеПисьма КАК ВсеЭлектронныеПисьма
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействий
	|		ПО ВсеЭлектронныеПисьма.Ссылка = ПредметыПапкиВзаимодействий.Взаимодействие
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПапкиЭлектронныхПисем КАК ПапкиЭлектронныхПисем
	|		ПО (ПредметыПапкиВзаимодействий.ПапкаЭлектронногоПисьма = ПапкиЭлектронныхПисем.Ссылка)
	|
	|УПОРЯДОЧИТЬ ПО
	|	ВсеЭлектронныеПисьма.Приоритет Возр,
	|	Дата УБЫВ";
	
	Запрос.УстановитьПараметр("ТаблицаИдентификаторов", ТаблицаИдентификаторов);
	Запрос.УстановитьПараметр("УчетнаяЗапись", УчетнаяЗапись);
	Запрос.УстановитьПараметр("ИдентификаторСообщения", Письмо.ИдентификаторСообщения);
	
	НачалоВыполненияЗапроса = ТекущаяУниверсальнаяДатаВМиллисекундах();
	Выборка = Запрос.Выполнить().Выбрать();
	ВремяВыполненияЗапроса =  Окр((ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоВыполненияЗапроса)/1000, 2);
	
	Если ВремяВыполненияЗапроса > 1 Тогда
		
		ТекстЗаписиЖурнала = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Запрос по получению данных писем основания загружаемого письма выполнялся дольше %1 сек, это дольше ожидаемого.'"),
			ВремяВыполненияЗапроса);
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Информация,
			Письмо, ТекстЗаписиЖурнала);
		
	КонецЕсли;
	
	Если Выборка.Следующий() Тогда
		
		Результат.Предмет = Выборка.Предмет;
		Если Выборка.Приоритет = 0 Тогда
			Письмо.ВзаимодействиеОснование = Выборка.Ссылка;
			Если ПомещатьПисьмоВПапкуПисьмаОснования И Не Выборка.ПредопределеннаяПапка Тогда
				Результат.Папка = Выборка.Папка;
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Процедура ЗаполнитьКонтактыВЗагружаемомПисьме(Письмо, ЭтоИсходящееПисьмо)
	
	СоответствиеКонтактов = СоответствиеКонтактовВПисьме(Письмо.ВзаимодействиеОснование);

	НеопределенныеАдреса = Новый Массив;
	УстановитьКонтактыВПисьме(Письмо, СоответствиеКонтактов, НеопределенныеАдреса, ЭтоИсходящееПисьмо);

	// Если есть неопределенные адреса, то поищем их по контактной информации.
	СоответствиеКонтактов = НайтиАдресаЭлектроннойПочтыВКонтактнойИнформации(НеопределенныеАдреса);
	Если СоответствиеКонтактов.Количество() > 0 Тогда
		УстановитьКонтактыВПисьме(Письмо, СоответствиеКонтактов, НеопределенныеАдреса, ЭтоИсходящееПисьмо);
	КонецЕсли;
	
	Письмо.СписокПолучателейПисьма = ВзаимодействияКлиентСервер.ПолучитьПредставлениеСпискаАдресатов(Письмо.ПолучателиПисьма, Ложь);
	Письмо.СписокПолучателейКопий  = ВзаимодействияКлиентСервер.ПолучитьПредставлениеСпискаАдресатов(Письмо.ПолучателиКопий, Ложь);
	Если ТипЗнч(Письмо) = Тип("ДокументОбъект.ЭлектронноеПисьмоИсходящее") Тогда
		Письмо.СписокПолучателейСкрытыхКопий  = ВзаимодействияКлиентСервер.ПолучитьПредставлениеСпискаАдресатов(Письмо.ПолучателиКопий, Ложь);
	КонецЕсли;
	
КонецПроцедуры

Функция НайтиАдресаЭлектроннойПочтыВКонтактнойИнформации(МассивАдресов)

	СоответствиеКонтактов = Новый Соответствие;

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	Контакты.Ссылка,
	|	Контакты.АдресЭП КАК АдресЭП
	|ИЗ
	|	(ВЫБРАТЬ
	|		КонтактнаяИнформация.Ссылка КАК Ссылка,
	|		КонтактнаяИнформация.АдресЭП КАК АдресЭП
	|	ИЗ
	|		Справочник.Пользователи.КонтактнаяИнформация КАК КонтактнаяИнформация
	|	ГДЕ
	|		КонтактнаяИнформация.АдресЭП В(&МассивАдресов)
	|		И КонтактнаяИнформация.Тип = &Тип
	|		И НЕ(КонтактнаяИнформация.Ссылка.ПометкаУдаления)
	|		И &ТекстЗапросаДругиеТипыКонтактов)КАК Контакты
	|ИТОГИ ПО
	|	АдресЭП
	|";
	
	ТекстЗапросаДругиеТипыКонтактов = "";
	МассивОписанияТиповКонтактов = ВзаимодействияКлиентСервер.ОписанияКонтактов();
	Для каждого ЭлементМассиваОписания Из МассивОписанияТиповКонтактов Цикл
		
		Если ЭлементМассиваОписания.Имя = "Пользователи" Тогда
			Продолжить;
		КонецЕсли;	
		
		ТекстЗапросаДругиеТипыКонтактов = ТекстЗапросаДругиеТипыКонтактов + "
		|ОБЪЕДИНИТЬ ВСЕ
		|";
		
		ТекстЗапросаДругиеТипыКонтактов = ТекстЗапросаДругиеТипыКонтактов + "
		|ВЫБРАТЬ
		|		КонтактнаяИнформация.Ссылка КАК Ссылка,
		|		КонтактнаяИнформация.АдресЭП КАК АдресЭП
		|ИЗ
		|	&ТаблицаКонтактнаяИнформация КАК КонтактнаяИнформация
		|ГДЕ
		|	КонтактнаяИнформация.АдресЭП В(&МассивАдресов)
		|	И КонтактнаяИнформация.Тип = &Тип
		|	И (НЕ КонтактнаяИнформация.Ссылка.ПометкаУдаления)
		|";
		
		ТекстЗапросаДругиеТипыКонтактов = СтрЗаменить(ТекстЗапросаДругиеТипыКонтактов, "&ТаблицаКонтактнаяИнформация", "Справочник." + ЭлементМассиваОписания.Имя + ".КонтактнаяИнформация");
		
	КонецЦикла;
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "И &ТекстЗапросаДругиеТипыКонтактов", ТекстЗапросаДругиеТипыКонтактов);

	Запрос.УстановитьПараметр("МассивАдресов", МассивАдресов);
	Запрос.УстановитьПараметр("Тип", Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты);
	
	Выборка = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	Пока Выборка.Следующий() Цикл
		ВыборкаПоСсылкам = Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
		Если (ВыборкаПоСсылкам.Следующий()) Тогда
			СоответствиеКонтактов.Вставить(ВРег(Выборка.АдресЭП), ВыборкаПоСсылкам.Ссылка);
		КонецЕсли;
	КонецЦикла;

	Возврат СоответствиеКонтактов;

КонецФункции

Процедура УстановитьКонтактыВПисьме(Письмо, СоответствиеКонтактов, НеопределенныеАдреса, ЭтоИсходящееПисьмо)
	
	Для Каждого СтрокаТаблицы Из Письмо.ПолучателиПисьма Цикл
		ОбработатьПоляКонтактИАдрес(СтрокаТаблицы.Адрес, СтрокаТаблицы.Контакт, СоответствиеКонтактов, НеопределенныеАдреса);
	КонецЦикла;
	
	Для Каждого СтрокаТаблицы Из Письмо.ПолучателиКопий Цикл
		ОбработатьПоляКонтактИАдрес(СтрокаТаблицы.Адрес, СтрокаТаблицы.Контакт, СоответствиеКонтактов, НеопределенныеАдреса);
	КонецЦикла;
	
	Для Каждого СтрокаТаблицы Из Письмо.ПолучателиОтвета Цикл
		ОбработатьПоляКонтактИАдрес(СтрокаТаблицы.Адрес, СтрокаТаблицы.Контакт, СоответствиеКонтактов, НеопределенныеАдреса);
	КонецЦикла;
	
	Если ЭтоИсходящееПисьмо Тогда
		Для Каждого СтрокаТаблицы Из Письмо.ПолучателиСкрытыхКопий Цикл
			ОбработатьПоляКонтактИАдрес(СтрокаТаблицы.Адрес, СтрокаТаблицы.Контакт, СоответствиеКонтактов, НеопределенныеАдреса);
		КонецЦикла;
	Иначе
		ОбработатьПоляКонтактИАдрес(Письмо.ОтправительАдрес, Письмо.ОтправительКонтакт, СоответствиеКонтактов, НеопределенныеАдреса);
	КонецЕсли;

КонецПроцедуры

Процедура ОбработатьПоляКонтактИАдрес(Адрес, Контакт, СоответствиеКонтактов, НеопределенныеАдреса)
	
	Если ЗначениеЗаполнено(Контакт) И ТипЗнч(Контакт) <> Тип("Строка") Тогда
		Возврат;
	КонецЕсли;
	
	НайденныйКонтакт = СоответствиеКонтактов.Получить(ВРег(Адрес));
	Если НайденныйКонтакт <> Неопределено И ТипЗнч(НайденныйКонтакт) <> Тип("Строка") Тогда
		Контакт = НайденныйКонтакт;
		Возврат;
	КонецЕсли;
	
	Если НеопределенныеАдреса.Найти(Адрес) = Неопределено Тогда
		НеопределенныеАдреса.Добавить(Адрес);
	КонецЕсли;
	
КонецПроцедуры

Функция СоответствиеКонтактовВПисьме(Письмо)
	
	СоответствиеКонтактов = Новый Соответствие;
	Если Не ЗначениеЗаполнено(Письмо) Тогда
		Возврат СоответствиеКонтактов;
	КонецЕсли;
	
	Если ТипЗнч(Письмо) = Тип("ДокументСсылка.ЭлектронноеПисьмоИсходящее") Тогда
		
		ТекстЗапросаОтправитель = "
		|	
		|	ОБЪЕДИНИТЬ ВСЕ
		|	
		|";
		
		ТекстЗапросаОтправитель = ТекстЗапросаОтправитель + "
		|ВЫБРАТЬ
		|		ЭлектронноеПисьмоВходящее.ОтправительАдрес   КАК Адрес,
		|		ЭлектронноеПисьмоВходящее.ОтправительКонтакт КАК Контакт
		|	ИЗ
		|		Документ.ЭлектронноеПисьмоВходящее КАК ЭлектронноеПисьмоВходящее
		|	ГДЕ
		|		ЭлектронноеПисьмоВходящее.Ссылка = &Письмо";
		
	Иначе
		
		ТекстЗапросаОтправитель = "";
		
	КонецЕсли;

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	Адреса.Адрес,
	|	Адреса.Контакт
	|ИЗ
	|	(ВЫБРАТЬ
	|		Получатели.Адрес    КАК Адрес,
	|		Получатели.Контакт  КАК Контакт
	|	ИЗ
	|		&ИмяТаблицыПолучателиПисьма КАК Получатели
	|	ГДЕ
	|		Получатели.Ссылка = &Письмо
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		Получатели.Адрес,
	|		Получатели.Контакт
	|	ИЗ
	|		&ИмяТаблицыПолучателиКопий  КАК Получатели
	|	ГДЕ
	|		Получатели.Ссылка = &Письмо
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		Получатели.Адрес,
	|		Получатели.Контакт
	|	ИЗ
	|		&ИмяТаблицыПолучателиОтвет КАК Получатели
	|	ГДЕ
	|		Получатели.Ссылка = &Письмо И &ТекстЗапросаОтправитель) КАК Адреса";
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "И &ТекстЗапросаОтправитель", ТекстЗапросаОтправитель);
	Запрос.УстановитьПараметр("Письмо", Письмо);
	
	Если ТипЗнч(Письмо) = Тип("ДокументСсылка.ЭлектронноеПисьмоИсходящее") Тогда
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИмяТаблицыПолучателиПисьма", "Документ.ЭлектронноеПисьмоИсходящее.ПолучателиПисьма");
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИмяТаблицыПолучателиКопий", "Документ.ЭлектронноеПисьмоИсходящее.ПолучателиКопий");
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИмяТаблицыПолучателиОтвет", "Документ.ЭлектронноеПисьмоИсходящее.ПолучателиОтвета");
	Иначе
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИмяТаблицыПолучателиПисьма", "Документ.ЭлектронноеПисьмоВходящее.ПолучателиПисьма");
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИмяТаблицыПолучателиКопий", "Документ.ЭлектронноеПисьмоВходящее.ПолучателиКопий");
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИмяТаблицыПолучателиОтвет", "Документ.ЭлектронноеПисьмоВходящее.ПолучателиОтвета");
	КонецЕсли;
	
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Если ТипЗнч(Выборка.Контакт) <> Тип("Строка") Тогда
			СоответствиеКонтактов.Вставить(Выборка.Адрес, Выборка.Контакт);
		КонецЕсли;
	КонецЦикла;

	Возврат СоответствиеКонтактов;
	
КонецФункции

Процедура ЗаписатьИдентификаторПолученногоПисьма(УчетнаяЗапись, Идентификатор, ДатаПолучения)

	Запись = РегистрыСведений.ИдентификаторыПолученныхЭлектронныхПисем.СоздатьМенеджерЗаписи();
	Запись.УчетнаяЗапись = УчетнаяЗапись;
	Запись.Идентификатор = Идентификатор;
	Запись.ДатаПолучения = ДатаПолучения;
	Запись.Записать();

КонецПроцедуры

Функция ИзПисьмаПолучитьИдентификаторОснования(Сообщение)

	СтрокаИдентификаторы = СокрЛП(Сообщение.ПолучитьПолеЗаголовка("In-Reply-To", "Строка"));
	
	Позиция = СтрНайти(СтрокаИдентификаторы, "<");
	Если Позиция <> 0 Тогда
		СтрокаИдентификаторы = Сред(СтрокаИдентификаторы, Позиция+1);
	КонецЕсли;
	
	Позиция = СтрНайти(СтрокаИдентификаторы, ">");
	Если Позиция <> 0 Тогда
		СтрокаИдентификаторы = Лев(СтрокаИдентификаторы, Позиция-1);
	КонецЕсли;

	Возврат СтрокаИдентификаторы;

КонецФункции

Процедура УстановитьТекстПисьма(Письмо, Сообщение) Экспорт
	
	ТекстHTML = "";
	ТекстПростой = "";
	ТекстРазмеченный = "";

	Для Каждого ТекстПочтовогоСообщения Из Сообщение.Тексты Цикл
		Если ТекстПочтовогоСообщения.ТипТекста = ТипТекстаПочтовогоСообщения.HTML Тогда
			
			ТекстHTML = ТекстHTML + ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(ТекстПочтовогоСообщения.Текст);
			
		ИначеЕсли ТекстПочтовогоСообщения.ТипТекста = ТипТекстаПочтовогоСообщения.ПростойТекст Тогда
			
			ТекстПростой = ТекстПростой + ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(ТекстПочтовогоСообщения.Текст);
			
		ИначеЕсли ТекстПочтовогоСообщения.ТипТекста = ТипТекстаПочтовогоСообщения.РазмеченныйТекст Тогда
			ТекстРазмеченный = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(ТекстПочтовогоСообщения.Текст);
			
		КонецЕсли;
	КонецЦикла;
	
	Если ТекстHTML <> "" Тогда
		Письмо.ТипТекста = Перечисления.ТипыТекстовЭлектронныхПисем.HTML;
		Письмо.ТекстHTML = ТекстHTML;
		Письмо.Текст = ?(ТекстПростой <> "", ТекстПростой, ПолучитьПростойТекстИзHTML(ТекстHTML));
		
	ИначеЕсли ТекстРазмеченный <> "" Тогда
		Письмо.ТипТекста = Перечисления.ТипыТекстовЭлектронныхПисем.РазмеченныйТекст;
		Письмо.Текст = ТекстРазмеченный;
		
	Иначе
		Письмо.ТипТекста = Перечисления.ТипыТекстовЭлектронныхПисем.ПростойТекст;
		Письмо.Текст = ТекстПростой;
		
	КонецЕсли;
	
КонецПроцедуры

Функция АдресОтправителяИнтернетПочтовогоСообщения(Отправитель)
	
	Если ТипЗнч(Отправитель) = Тип("ИнтернетПочтовыйАдрес") Тогда
		ОтправительАдрес = Отправитель.Адрес;
	Иначе
		ОтправительАдрес = Отправитель;
	КонецЕсли;
	
	Возврат ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(ОтправительАдрес, "");
	
КонецФункции

Процедура ИзменитьДоменВПочтовомАдресеЕслиНеобходимо(ПочтовыйАдрес)
	
	СтруктураАдреса =  СтруктураАдресаЭлектроннойПочты(ПочтовыйАдрес);
	Если СтруктураАдреса = Неопределено Тогда
		Возврат;
	КонецЕсли;
	Если Метаданные.ОбщиеМодули.Найти("ВзаимодействияЛокализация") <> Неопределено Тогда 
		МодульВзаимодействияЛокализация = ОбщегоНазначения.ОбщийМодуль("ВзаимодействияЛокализация");
		СинонимыДоменовЭлектроннойПочты = МодульВзаимодействияЛокализация.СинонимыДоменовЭлектроннойПочты();
		ДоменНаКоторыйНеобходимоЗаменить = СинонимыДоменовЭлектроннойПочты[СтруктураАдреса.Домен];
		Если ДоменНаКоторыйНеобходимоЗаменить <> Неопределено Тогда
			ПочтовыйАдрес = СтруктураАдреса.ИмяПочтовогоЯщика + "@" + ДоменНаКоторыйНеобходимоЗаменить;
		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

Функция ИменаАктивныхПапок(Почта)

	Результат = Новый Массив;
	 
	ИменаАктивныхПапок     = Почта.ПолучитьПочтовыеЯщикиПоПодписке();
	Если ИменаАктивныхПапок.Количество() = 0 Тогда
		ИменаАктивныхПапок = Почта.ПолучитьПочтовыеЯщики();
	КонецЕсли;
	
	Разделитель = ""; 
	Попытка
		Разделитель = Почта.СимволРазделитель;
	Исключение
		// АПК:280 Некоторые почтовые сервера не поддерживают эту команду.
	КонецПопытки;
	
	МассивИгнорируемыхИмен  = ИменаПапокНеДляЗагрузкиПисем();
	
	Для Каждого ИмяАктивнойПапки Из ИменаАктивныхПапок Цикл
		
		Если Не ПустаяСтрока(Разделитель) Тогда
			
			МассивСтрокИмениПапки = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивСлов(ИмяАктивнойПапки,Разделитель);
			Если МассивСтрокИмениПапки.Количество() = 0 Тогда
				Продолжить;
			КонецЕсли;
			ИмяПапкиБезРазделителя = МассивСтрокИмениПапки[МассивСтрокИмениПапки.Количество()-1];
			Если ПустаяСтрока(ИмяПапкиБезРазделителя) Тогда
				Продолжить;
			КонецЕсли;
			Если Лев(ИмяПапкиБезРазделителя,1) = "[" И Прав(ИмяПапкиБезРазделителя,1) = "]" Тогда
				Продолжить;
			КонецЕсли;
			
			Если МассивИгнорируемыхИмен.Найти(НРег(ИмяПапкиБезРазделителя)) <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
		Иначе
			
			Если Лев(ИмяАктивнойПапки,1) = "[" И Прав(ИмяАктивнойПапки,1) = "]" Тогда
				Продолжить;
			КонецЕсли;
			
			Если МассивИгнорируемыхИмен.Найти(НРег(ИмяАктивнойПапки)) <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
		КонецЕсли;
		
		Результат.Добавить(ИмяАктивнойПапки);
		
	КонецЦикла;

	Возврат Результат;
	
КонецФункции

Функция ИменаПапокНеДляЗагрузкиПисем()

	Результат = Новый Массив;
	Результат.Добавить("спам");
	Результат.Добавить("удаленные");
	Результат.Добавить("черновики");
	Результат.Добавить("корзина");
	Результат.Добавить("spam");
	Результат.Добавить("trash");
	Результат.Добавить("drafts");
	Результат.Добавить("draftBox");
	Результат.Добавить("deleted");
	Результат.Добавить("junk");
	Результат.Добавить("bulk mail");
	Возврат Результат;

КонецФункции

Процедура ОпределитьЗагруженныеРанееПодчиненныеПисьма(УчетнаяЗапись, ПолученныеПисьма);
	
	Если ПолученныеПисьма.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	МассивДобавляемыхКОбработкеПисем = Новый Массив;
	МетаданныеИсходящееПисьмо = Метаданные.Документы.ЭлектронноеПисьмоИсходящее;
	МетаданныеВходящееПисьмо = Метаданные.Документы.ЭлектронноеПисьмоВходящее;
	
	Запрос = Новый Запрос;
	Запрос.Текст = "
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоИсходящее.Ссылка,
	|	ЭлектронноеПисьмоИсходящее.ИдентификаторСообщения
	|ПОМЕСТИТЬ ПолученныеПисьмаИдентификаторы
	|ИЗ
	|	Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
	|ГДЕ
	|	ЭлектронноеПисьмоИсходящее.Ссылка В(&МассивПисем)
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоВходящее.Ссылка,
	|	ЭлектронноеПисьмоВходящее.ИдентификаторСообщения
	|ИЗ
	|	Документ.ЭлектронноеПисьмоВходящее КАК ЭлектронноеПисьмоВходящее
	|ГДЕ
	|	ЭлектронноеПисьмоВходящее.Ссылка В(&МассивПисем)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоИсходящее.Ссылка                                      КАК Письмо,
	|	ЭлектронноеПисьмоИсходящее.ВзаимодействиеОснование                     КАК ТекущееОснование,
	|	ПолученныеПисьмаИдентификаторы.Ссылка                                  КАК СсылкаНаОснование,
	|	ЕСТЬNULL(ПредметыПапкиВзаимодействийОснования.Предмет, НЕОПРЕДЕЛЕНО)   КАК ПредметПисьмаОснования,
	|	ЕСТЬNULL(ПредметыПапкиВзаимодействийПодчиненные.Предмет, НЕОПРЕДЕЛЕНО) КАК ПредметПисьмаПодчиненное
	|ИЗ
	|	ПолученныеПисьмаИдентификаторы КАК ПолученныеПисьмаИдентификаторы
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
	|		ПО ПолученныеПисьмаИдентификаторы.ИдентификаторСообщения = ЭлектронноеПисьмоИсходящее.ИдентификаторОснования
	|			И (ЭлектронноеПисьмоИсходящее.ВзаимодействиеОснование <> ПолученныеПисьмаИдентификаторы.Ссылка)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействийПодчиненные
	|		ПО (ЭлектронноеПисьмоИсходящее.Ссылка = ПредметыПапкиВзаимодействийПодчиненные.Взаимодействие)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействийОснования
	|		ПО ПолученныеПисьмаИдентификаторы.Ссылка = ПредметыПапкиВзаимодействийОснования.Взаимодействие
	|ГДЕ
	|	ЭлектронноеПисьмоИсходящее.УчетнаяЗапись = &УчетнаяЗапись
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ЭлектронноеПисьмоВходящее.Ссылка,
	|	ЭлектронноеПисьмоВходящее.ВзаимодействиеОснование,
	|	ПолученныеПисьмаИдентификаторы.Ссылка,
	|	ЕСТЬNULL(ПредметыПапкиВзаимодействийОснования.Предмет, НЕОПРЕДЕЛЕНО),
	|	ЕСТЬNULL(ПредметыПапкиВзаимодействийПодчиненные.Предмет, НЕОПРЕДЕЛЕНО) 
	|ИЗ
	|	ПолученныеПисьмаИдентификаторы КАК ПолученныеПисьмаИдентификаторы
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЭлектронноеПисьмоВходящее КАК ЭлектронноеПисьмоВходящее
	|		ПО ПолученныеПисьмаИдентификаторы.ИдентификаторСообщения = ЭлектронноеПисьмоВходящее.ИдентификаторОснования
	|			И (ЭлектронноеПисьмоВходящее.ВзаимодействиеОснование <> ПолученныеПисьмаИдентификаторы.Ссылка)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействийПодчиненные
	|		ПО (ЭлектронноеПисьмоВходящее.Ссылка = ПредметыПапкиВзаимодействийПодчиненные.Взаимодействие)
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействийОснования
	|		ПО ПолученныеПисьмаИдентификаторы.Ссылка = ПредметыПапкиВзаимодействийОснования.Взаимодействие
	|ГДЕ
	|	ЭлектронноеПисьмоВходящее.УчетнаяЗапись = &УчетнаяЗапись";
	
	Запрос.УстановитьПараметр("УчетнаяЗапись", УчетнаяЗапись);
	Запрос.УстановитьПараметр("МассивПисем", ПолученныеПисьма);
	
	Результат = Запрос.Выполнить();
	Если Результат.Пустой() Тогда
		Возврат;
	КонецЕсли;
	
	Выборка = Результат.Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		НачатьТранзакцию();
		
		Попытка
			
			МетаданныеДокумента = ?(ТипЗнч(Выборка.Письмо) = Тип("ДокументСсылка.ЭлектронноеПисьмоВходящее"),
			                        МетаданныеВходящееПисьмо, МетаданныеИсходящееПисьмо);
			
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить(МетаданныеДокумента.ПолноеИмя());
			ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Письмо);
			РегистрыСведений.ПредметыПапкиВзаимодействий.ЗаблокироватьПредметыПапокВзаимодействий(Блокировка, Выборка.Письмо);
			РегистрыСведений.ПредметыПапкиВзаимодействий.ЗаблокироватьПредметыПапокВзаимодействий(Блокировка, Выборка.СсылкаНаОснование);
			Блокировка.Заблокировать();
			
			ПисьмоОбъект = Выборка.Письмо.ПолучитьОбъект(); // ДокументОбъект.ЭлектронноеПисьмоВходящее, ДокументОбъект.ЭлектронноеПисьмоИсходящее - 
				ПисьмоОбъект.ВзаимодействиеОснование = Выборка.СсылкаНаОснование;
			ПисьмоОбъект.Записать();
			
			Если Выборка.ПредметПисьмаОснования <> Выборка.ПредметПисьмаПодчиненное Тогда
				
				Если Выборка.ПредметПисьмаПодчиненное = Выборка.Письмо Тогда
					
					Взаимодействия.УстановитьПредмет(Выборка.Письмо, Выборка.ПредметПисьмаОснования, Ложь);
					
				ИначеЕсли НЕ ВзаимодействияКлиентСервер.ЯвляетсяПредметом(Выборка.ПредметПисьмаПодчиненное) Тогда
					
					Если ВзаимодействияКлиентСервер.ЯвляетсяПредметом(Выборка.ПредметПисьмаОснования) Тогда
						Взаимодействия.УстановитьПредмет(Выборка.Письмо, Выборка.ПредметПисьмаОснования, Ложь);
						МассивДобавляемыхКОбработкеПисем.Добавить(Выборка.Письмо);
					Иначе 
						Взаимодействия.УстановитьПредмет(Выборка.СсылкаНаОснование, Выборка.ПредметПисьмаПодчиненное, Ложь);
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЕсли;
			
			ЗафиксироватьТранзакцию();
		
		Исключение
			ОтменитьТранзакцию();
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не установить письмо основание у %1 по причине %2'"), 
				Выборка.Письмо, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Предупреждение,
				МетаданныеДокумента, Выборка.Письмо, ТекстСообщения);
		КонецПопытки;
	
	КонецЦикла;
	 
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ПолученныеПисьма, МассивДобавляемыхКОбработкеПисем, Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Работа с вложения электронных писем.

Функция ИнтернетПочтовоеСообщениеИзДвоичныхДанных(ДвоичныеДанные) 
	
	ПочтовоеСообщение = Новый ИнтернетПочтовоеСообщение;
	ПочтовоеСообщение.УстановитьИсходныеДанные(ДвоичныеДанные);
	
	Возврат ПочтовоеСообщение;
	
КонецФункции

Процедура ЗаписатьВложениеЭлектронногоПисьма(Объект, Вложение,МассивПодписей,КоличествоПустыхИменВоВложениях)
	
	ПисьмоСсылка = Объект.Ссылка;
	Размер = 0;
	ЭтоВложениеПисьмо = Ложь;
	
	Если ТипЗнч(Вложение.Данные) = Тип("ДвоичныеДанные") Тогда
		
		ДанныеВложения = Вложение.Данные;
		ИмяФайла = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(Вложение.ИмяФайла, "");
		ЭтоВложениеПисьмо = ФайлЯвляетсяЭлектроннымПисьмом(ИмяФайла, ДанныеВложения);
		
	Иначе
		
		ДанныеВложения = Вложение.Данные.ПолучитьИсходныеДанные();
		ИмяФайла = Взаимодействия.ПредставлениеПисьма(Вложение.Данные.Тема, Вложение.Данные.ДатаПолучения) + ".eml";
		ЭтоВложениеПисьмо = Истина;
		
	КонецЕсли;
	
	Размер = ДанныеВложения.Размер();
	Адрес = ПоместитьВоВременноеХранилище(ДанныеВложения, "");
	
	Если Не ПустаяСтрока(Вложение.Идентификатор) Тогда
		
		Если СтрНайти(Объект.ТекстHTML, Вложение.Идентификатор) = 0 
			Или (СтрНайти(Объект.ТекстHTML, Вложение.Имя) > 0 
			И СтрНайти(Вложение.Идентификатор, Вложение.Имя + "@") = 0
			И СтрНайти(Объект.ТекстHTML, "alt=" + """" + Вложение.Имя + """") = 0) Тогда
			
			Вложение.Идентификатор = "";
			
		КонецЕсли;
		
	КонецЕсли;
	
	ЕстьПодписи = (МассивПодписей.Количество() > 0)
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись");
		
	ЭтоОтображаемыйФайл = НЕ ПустаяСтрока(Вложение.Идентификатор);
	
	ПараметрыВложения = Новый Структура;
	ПараметрыВложения.Вставить("ИмяФайла", ИмяФайла);
	ПараметрыВложения.Вставить("Размер", Размер);
	Если ЭтоОтображаемыйФайл Тогда
		ПараметрыВложения.Вставить("ИДФайлаЭлектронногоПисьма", Вложение.Идентификатор);
	КонецЕсли;
	Если ЭтоВложениеПисьмо Тогда
		ПараметрыВложения.Вставить("ЭтоВложениеПисьмо", Истина);
	КонецЕсли;
	Если ЕстьПодписи Тогда
		ПараметрыВложения.Вставить("ПодписанЭП", Истина);
	КонецЕсли;
	
	Если СтрЗаканчиваетсяНа(ИмяФайла, ".p7m") Тогда
		
		Зашифрован = Истина;
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
			МодульЭлектроннаяПодписьСлужебныйКлиентСервер = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьСлужебныйКлиентСервер");
			ТипДанных = МодульЭлектроннаяПодписьСлужебныйКлиентСервер.ОпределитьТипДанных(ДанныеВложения);
			Если ТипДанных <> "ЗашифрованныеДанные" Тогда
				Зашифрован = Ложь;
			КонецЕсли;
		КонецЕсли;
		
		Если Зашифрован Тогда
			ПараметрыВложения.Вставить("Зашифрован", Зашифрован);
			ПараметрыВложения.Вставить("ИмяФайла", Лев(ИмяФайла, СтрДлина(ИмяФайла) - 4));
		КонецЕсли;
		
	КонецЕсли;
	
	ВложениеПисьмаСсылка = ЗаписатьВложениеЭлектронногоПисьмаИзВременногоХранилища(
		ПисьмоСсылка, Адрес, ПараметрыВложения, КоличествоПустыхИменВоВложениях);
	
	Если ЕстьПодписи Тогда

		МодульЭлектроннаяПодпись = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодпись");
		МодульЭлектроннаяПодписьКлиентСервер= ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьКлиентСервер");
		
		Для Каждого ПодписьВложения Из МассивПодписей Цикл
			
			Попытка
				ДанныеПодписиВложения = МодульЭлектроннаяПодпись.ПодписьВКодировкеDER(ПодписьВложения.Данные);
			Исключение
				ТекстСобытия = НСтр("ru = 'Не удалось прочитать данные подписи вложения %1: %2'");
				ОшибкаНеУдалосьПрочитатьДанныеПодписи = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					ТекстСобытия, ВложениеПисьмаСсылка, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Информация, , , ОшибкаНеУдалосьПрочитатьДанныеПодписи);
				Продолжить;
			КонецПопытки;
			
			ДанныеПодписи = МодульЭлектроннаяПодписьКлиентСервер.НовыеСвойстваПодписи();
			ДанныеПодписи.Подпись = ДанныеПодписиВложения;
			РезультатЧтенияСвойствПодписи = МодульЭлектроннаяПодпись.СвойстваПодписи(ДанныеПодписиВложения);
			
			Если РезультатЧтенияСвойствПодписи.Успех <> Ложь Тогда
				ЗаполнитьЗначенияСвойств(ДанныеПодписи, РезультатЧтенияСвойствПодписи);
				ДанныеПодписи.Вставить("ДатаПодписиИзМетки", РезультатЧтенияСвойствПодписи.ДатаПодписиИзМетки);
				ДанныеПодписи.Вставить("НеподтвержденнаяДатаПодписи", РезультатЧтенияСвойствПодписи.НеподтвержденнаяДатаПодписи);
			Иначе
				ТекстСобытия = НСтр("ru = 'Не удалось прочитать данные подписи вложения %1: %2'");
				ОшибкаНеУдалосьПрочитатьДанныеПодписи = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					ТекстСобытия, ВложениеПисьмаСсылка, РезультатЧтенияСвойствПодписи.ТекстОшибки);
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Информация, , , ОшибкаНеУдалосьПрочитатьДанныеПодписи);
				Продолжить;
			КонецЕсли;
			
			ДанныеПодписи.Комментарий = НСтр("ru = 'Вложение электронного письма'");
			
			РаботаСФайлами.ДобавитьПодписьКФайлу(ВложениеПисьмаСсылка, ДанныеПодписи);
			
		КонецЦикла;
	
	КонецЕсли;
	
	УдалитьИзВременногоХранилища(Адрес);
	
КонецПроцедуры

// Параметры:
//  Письмо                         - ДокументСсылка - документ электронное письмо для которого необходимо получить вложения.
//  ФормироватьРазмерПредставление - Булево - признак того, что в результате запроса будет пустая строковая колонка РазмерПредставление.
//  ТолькоСПустымИД                - Булево - если Истина, то будут получены только вложения без ИДФайлаЭлектронногоПисьма.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//     * Ссылка                    - СправочникСсылка.ЭлектронноеПисьмоВходящееПрисоединенныеФайлы
//                                 - СправочникСсылка.ЭлектронноеПисьмоИсходящееПрисоединенныеФайлы - 
//                                   ссылка на присоединенный файл.
//     * ИндексКартинки            - Число  - номер отображаемой картинки.
//     * ПодписанЭП                - Булево - признак того, что файл подписан электронной подписью.
//     * Размер                    - Число  - размер файла.
//     * ИДФайлаЭлектронногоПисьма - Строка - идентификатор картинки, которая отображается в тексте письма.
//     * ИмяФайла                  - Строка - имя файла.
//     * РазмерПредставление       - Строка - представление размера.
//
Функция ПолучитьВложенияЭлектронногоПисьма(Письмо,ФормироватьРазмерПредставление = Ложь, ТолькоСПустымИД = Ложь) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ДанныеПрисоединенныхФайловПисьма = Взаимодействия.ДанныеПрисоединенныхФайловПисьма(Письмо);
	ИмяОбъектаМетаданных = ДанныеПрисоединенныхФайловПисьма.ИмяСправочникаПрисоединенныхФайлов;
	ВладелецФайлов       = ДанныеПрисоединенныхФайловПисьма.ВладелецФайлов;
	
	Если ИмяОбъектаМетаданных = Неопределено Тогда
		Возврат Новый ТаблицаЗначений;
	КонецЕсли;
	
	Если ФормироватьРазмерПредставление Тогда
		ТекстРазмерПредставление = ",
		|ВЫРАЗИТЬ("""" КАК СТРОКА(20)) КАК РазмерПредставление";
	Иначе
		ТекстРазмерПредставление = "";
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Файлы.Ссылка                    КАК Ссылка,
	|	Файлы.ИндексКартинки            КАК ИндексКартинки,
	|	Файлы.Размер                    КАК Размер,
	|	Файлы.ИДФайлаЭлектронногоПисьма КАК ИДФайлаЭлектронногоПисьма,
	|	&ПодписанЭП                     КАК ПодписанЭП,
	|	ВЫБОР
	|		КОГДА Файлы.Расширение = &ПустаяСтрока
	|			ТОГДА Файлы.Наименование
	|		ИНАЧЕ Файлы.Наименование + ""."" + Файлы.Расширение
	|	КОНЕЦ КАК ИмяФайла" + ТекстРазмерПредставление + "
	|ИЗ
	|	Справочник." + ИмяОбъектаМетаданных + " КАК Файлы
	|ГДЕ
	|	Файлы.ВладелецФайла = &Письмо
	|	И НЕ Файлы.ПометкаУдаления";
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		СтрокаПодписанЭП = "Файлы.ПодписанЭП";
	Иначе
		СтрокаПодписанЭП = "ЛОЖЬ";
	КонецЕсли;
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ПодписанЭП", СтрокаПодписанЭП);
	
	Если ТолькоСПустымИД Тогда
		Запрос.Текст = Запрос.Текст + "
		| И Файлы.ИДФайлаЭлектронногоПисьма = """""; 
	КонецЕсли;
	
	Запрос.УстановитьПараметр("Письмо", ВладелецФайлов);
	Запрос.УстановитьПараметр("ПустаяСтрока","");
	
	ТаблицаКВозврату =  Запрос.Выполнить().Выгрузить(); // См. ПолучитьВложенияЭлектронногоПисьма
	
	Если ФормироватьРазмерПредставление Тогда
		Для каждого СтрокаТаблицы Из ТаблицаКВозврату Цикл
		
			СтрокаТаблицы.РазмерПредставление = 
				ВзаимодействияКлиентСервер.ПолучитьСтроковоеПредставлениеРазмераФайла(СтрокаТаблицы.Размер);
		
		КонецЦикла;
	КонецЕсли;
	
	ТаблицаКВозврату.Индексы.Добавить("ИДФайлаЭлектронногоПисьма");
	
	Возврат ТаблицаКВозврату;
	
КонецФункции

// Параметры:
//  Письмо                          - ДокументСсылка.ЭлектронноеПисьмоВходящее
//                                  - ДокументСсылка.ЭлектронноеПисьмоИсходящее -
//                                       письмо, чье вложение записывается.
//  АдресВоВременномХранилище       - Строка - адрес, по которому во временном хранилище находится вложение.
//  ПараметрыВложения               - Структура:
//     * ИмяФайла                  - Строка - имя файла-вложения.
//     * ИДФайлаЭлектронногоПисьма - Строка - идентификатор вложения.
//     * ЭтоВложениеПисьмо         - Булево - определяет, является ли это вложение письмом.
//     * ПодписанЭП                - Булево - определяет, подписано ли вложение электронной подписью.
//  КоличествоПустыхИменВоВложениях - Число - количество вложений письма, у которых нет имени.
//
// Возвращаемое значение:
//  СправочникСсылка.ЭлектронноеПисьмоВходящееПрисоединенныеФайлы
//  СправочникСсылка.ЭлектронноеПисьмоИсходящееПрисоединенныеФайлы
//
Функция ЗаписатьВложениеЭлектронногоПисьмаИзВременногоХранилища(
	Письмо,
	АдресВоВременномХранилище,
	ПараметрыВложения,
	КоличествоПустыхИменВоВложениях = 0) Экспорт
	
	ИмяФайлаДляРазбора = ПараметрыВложения.ИмяФайла;
	ИмяБезРасширения   = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяФайлаДляРазбора);
	РасширениеБезТочки = ОбщегоНазначенияКлиентСервер.ПолучитьРасширениеИмениФайла(ИмяБезРасширения);
	
	Если ПустаяСтрока(ИмяБезРасширения) Тогда
		
		ИмяБезРасширения =
			НСтр("ru = 'Вложение без имени'") + ?(КоличествоПустыхИменВоВложениях = 0, ""," " + Строка(КоличествоПустыхИменВоВложениях + 1));
		КоличествоПустыхИменВоВложениях = КоличествоПустыхИменВоВложениях + 1;
		
	Иначе
		ИмяБезРасширения =
			?(РасширениеБезТочки = "",
			ИмяБезРасширения,
			Лев(ИмяБезРасширения, СтрДлина(ИмяБезРасширения) - СтрДлина(РасширениеБезТочки) - 1));
	КонецЕсли;
	
	ДополнительныеПараметры = Новый Массив;
	Если ПараметрыВложения.Свойство("ИДФайлаЭлектронногоПисьма") Тогда
		ДополнительныеПараметры.Добавить("ИДФайлаЭлектронногоПисьма");
	КонецЕсли;
	Если ПараметрыВложения.Свойство("ЭтоВложениеПисьмо") Тогда
		ДополнительныеПараметры.Добавить("ЭтоВложениеПисьмо");
	КонецЕсли;
	Если ПараметрыВложения.Свойство("ПодписанЭП") Тогда
		ДополнительныеПараметры.Добавить("ПодписанЭП");
	КонецЕсли;
	Если ПараметрыВложения.Свойство("Зашифрован") Тогда
		ДополнительныеПараметры.Добавить("Зашифрован");
	КонецЕсли;
	
	ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла(ДополнительныеПараметры);
	ПараметрыФайла.ВладелецФайлов = Письмо;
	ПараметрыФайла.ИмяБезРасширения = ИмяБезРасширения;
	ПараметрыФайла.РасширениеБезТочки = РасширениеБезТочки;
	ПараметрыФайла.ВремяИзмененияУниверсальное = Неопределено;
	
	Если ПараметрыВложения.Свойство("ИДФайлаЭлектронногоПисьма") Тогда
		ПараметрыФайла.ИДФайлаЭлектронногоПисьма = ПараметрыВложения.ИДФайлаЭлектронногоПисьма;
	КонецЕсли;
	Если ПараметрыВложения.Свойство("ЭтоВложениеПисьмо") Тогда
		ПараметрыФайла.ЭтоВложениеПисьмо = ПараметрыВложения.ЭтоВложениеПисьмо;
	КонецЕсли;
	Если ПараметрыВложения.Свойство("ПодписанЭП") Тогда
		ПараметрыФайла.ПодписанЭП = ПараметрыВложения.ПодписанЭП;
	КонецЕсли;
	Если ПараметрыВложения.Свойство("Зашифрован") Тогда
		ПараметрыФайла.Зашифрован = ПараметрыВложения.Зашифрован;
	КонецЕсли;
	
	Возврат РаботаСФайлами.ДобавитьФайл(
		ПараметрыФайла,
		АдресВоВременномХранилище,
		"");
	
КонецФункции

Функция ЗаписатьВложениеЭлектронногоПисьмаСкопировавВложениеДругогоПисьма(
	Письмо,
	СсылкаНаФайл,
	УникальныйИдентификаторФормы) Экспорт
	
	ДанныеФайла = РаботаСФайлами.ДанныеФайла(
		СсылкаНаФайл, УникальныйИдентификаторФормы, Истина);
	
	ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
	ПараметрыФайла.ВладелецФайлов = Письмо;
	ПараметрыФайла.ИмяБезРасширения = ДанныеФайла.Наименование;
	ПараметрыФайла.РасширениеБезТочки = ДанныеФайла.Расширение;
	ПараметрыФайла.ВремяИзмененияУниверсальное = ДанныеФайла.ДатаМодификацииУниверсальная;
	
	Возврат РаботаСФайлами.ДобавитьФайл(
		ПараметрыФайла,
		ДанныеФайла.СсылкаНаДвоичныеДанныеФайла,
		"");
	
КонецФункции

// Параметры:
//  Письмо - ДокументСсылка - письмо, вложения которого будут удалены.
//
Процедура УдалитьВложенияУПисьма(Письмо) Экспорт

	ИмяОбъектаМетаданных = ИмяОбъектаМетаданныхПрисоединенныхФайловПисьма(Письмо);
	Если ИмяОбъектаМетаданных = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("Справочник." + ИмяОбъектаМетаданных);
	ЭлементБлокировки.УстановитьЗначение("ВладелецФайла", Письмо);
	Блокировка.Заблокировать();

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Файлы.Ссылка
	|ИЗ
	|	&ИмяСправочника КАК Файлы
	|ГДЕ
	|	Файлы.ВладелецФайла = &ВладелецФайла";
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИмяСправочника", "Справочник." + ИмяОбъектаМетаданных);
	
	Запрос.УстановитьПараметр("ВладелецФайла", Письмо);
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		Объект = Выборка.Ссылка.ПолучитьОбъект();
		Объект.Удалить();
	КонецЦикла;
	
КонецПроцедуры

// Проверяет, являются ли двоичные данные при десериализации ИнтернетПочтовоеСообщение.
//
// Параметры:
//  ДвоичныеДанные - ДвоичныеДанные - проверяемые двоичные данные.
//
// Возвращаемое значение:
//   Булево   - Истина, если двоичные данные корректно десериализуются в объект ИнтернетПочтовоеСообщение.
//
Функция ДвоичныеДанныеКорректноеИнтернетПочтовоеСообщение(ДвоичныеДанные)
	
	ПочтовоеСообщение = ИнтернетПочтовоеСообщениеИзДвоичныхДанных(ДвоичныеДанные);
	Возврат ПочтовоеСообщение.СтатусРазбора = СтатусРазбораИнтернетПочтовогоСообщения.ОшибокНеОбнаружено;
	
КонецФункции

Функция ФайлЯвляетсяЭлектроннымПисьмом(ИмяФайла, ДвоичныеДанные) Экспорт
	
	Если ВзаимодействияКлиентСервер.ЭтоФайлПисьмо(ИмяФайла)
		И ДвоичныеДанныеКорректноеИнтернетПочтовоеСообщение(ДвоичныеДанные) Тогда
		
		Возврат Истина;
		
	Иначе
		
		Возврат Ложь;
		
	КонецЕсли;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Уведомления о прочтении

// Возвращаемое значение:
//  СправочникСсылка.УчетныеЗаписиЭлектроннойПочты - учетная запись для отправки по умолчанию.
//
Функция ПолучитьУчетнуюЗаписьДляОтправкиПоУмолчанию() Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапросаПоДоступнымУчетнымЗаписям();
	
	Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.АвторизованныйПользователь());
	
	РезультатЗапроса = Запрос.Выполнить();
	Если РезультатЗапроса.Пустой() Тогда
		Возврат Справочники.УчетныеЗаписиЭлектроннойПочты.ПустаяСсылка();
	КонецЕсли;
	
	Выборка = РезультатЗапроса.Выбрать();
	Выборка.Следующий();
	Возврат Выборка.УчетнаяЗапись;
	
КонецФункции

Процедура ЗаписатьНеобходимостьОбработкиУведомленияОПрочтении(Письмо)
	
	Запись = РегистрыСведений.УведомленияОПрочтении.СоздатьМенеджерЗаписи();
	Запись.Письмо = Письмо;
	Запись.Записать();
	
КонецПроцедуры

// Устанавливает признак отправки уведомления о прочтении электронного письма.
//
// Параметры:
//  Письмо  - ДокументСсылка.ЭлектронноеПисьмоВходящее - письмо для которого устанавливается признак.
//  Отправлять  - Булево - если Истина, то признак будет установлен, снят если Ложь.
//
Процедура УстановитьПризнакОтправкиУведомления(Письмо, Отправлять) Экспорт

	УстановитьПривилегированныйРежим(Истина);
	
	Если Отправлять Тогда
		
		Запись = РегистрыСведений.УведомленияОПрочтении.СоздатьМенеджерЗаписи();
		Запись.Письмо = Письмо;
		Запись.ТребуетсяОтправка = Истина;
		Запись.ДатаПрочтения     = ПолучитьДатуСтрокойСоСмещениемGMT(ТекущаяДатаСеанса());
		Запись.Пользователь      = Пользователи.ТекущийПользователь();
		Запись.Записать();
		
	Иначе
		
		НаборЗаписей = РегистрыСведений.УведомленияОПрочтении.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.Письмо.Установить(Письмо);
		НаборЗаписей.Записать();
		
	КонецЕсли;

КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Прочее

Функция ПолучитьВажностьЭлектронногоПисьма(Важность)
	
	Если (Важность = ВажностьИнтернетПочтовогоСообщения.Высокая)
		ИЛИ (Важность = ВажностьИнтернетПочтовогоСообщения.Наивысшая) Тогда
		
		Возврат Перечисления.ВариантыВажностиВзаимодействия.Высокая;

	ИначеЕсли (Важность = ВажностьИнтернетПочтовогоСообщения.Наименьшая)
		ИЛИ (Важность = ВажностьИнтернетПочтовогоСообщения.Низкая) Тогда
		
		Возврат Перечисления.ВариантыВажностиВзаимодействия.Низкая;

	Иначе
		
		Возврат Перечисления.ВариантыВажностиВзаимодействия.Обычная;
		
	КонецЕсли;
	
КонецФункции

Функция ПолучитьПростойТекстИзHTML(ТекстHTML)
	
	Построитель = Новый ПостроительDOM;
	ЧтениеHTML = Новый ЧтениеHTML;
	ЧтениеHTML.УстановитьСтроку(ТекстHTML);
	ДокументHTML = Построитель.Прочитать(ЧтениеHTML);
	
	Возврат ДокументHTML.Тело.ТекстовоеСодержимое;
	
КонецФункции

Функция СформироватьТекстУведомленияОПрочтении(Выборка)

	ТекстУведомленияАнглийский = "
		|Your message from " + Выборка.ОтправительПредставление + "<" + Выборка.ОтправительАдрес + ">
		|Subject: " + Выборка.Тема + "
		|Sent " + Выборка.Дата + "
		|Has been read " +  Выборка.ДатаПрочтения + "
		|By Recipient " +Выборка.ИмяПользователя + "<" + Выборка.АдресЭлектроннойПочты + ">";
	
	ЛокализованноеУведомление = Символы.ПС + НСтр("ru = 'Сообщение от %1 < %2 >
		|Тема: %3
		|Отправленное %4
		|Было прочитано %5
		|Получателем %6 <%7>'");
	
	ЛокализованноеУведомление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ЛокализованноеУведомление,
		Выборка.ОтправительПредставление,
		Выборка.ОтправительАдрес,
		Выборка.Тема,
		Выборка.Дата,
		Выборка.ДатаПрочтения,
		Выборка.ИмяПользователя,
		Выборка.АдресЭлектроннойПочты);
	
	Возврат ЛокализованноеУведомление + Символы.ПС + Символы.ПС + ТекстУведомленияАнглийский;

КонецФункции

Функция ПолучитьДатуСтрокойСоСмещениемGMT(Дата)
	
	СмещениеВремениВСекундах = УниверсальноеВремя(Дата) - Дата; 
	ЧасыСмещения = Цел(СмещениеВремениВСекундах/3600); 
	СтрокаЧасыСмещения = ?(ЧасыСмещения > 0,"+","") + Формат(ЧасыСмещения,"ЧЦ=2; ЧДЦ=0; ЧН=00; ЧВН=");
	МинутыСмещения = СмещениеВремениВСекундах%3600;
	Если МинутыСмещения < 0 Тогда
		МинутыСмещения = - МинутыСмещения;
	КонецЕсли;
	СтрокаМинутыСмещения = Формат(МинутыСмещения,"ЧЦ=2; ЧДЦ=0; ЧН=00; ЧВН=");
	
	Возврат Формат(Дата,"ДЛФ=DT") + " GMT " + СтрокаЧасыСмещения + СтрокаМинутыСмещения;

КонецФункции

Процедура СоздатьПредопределеннуюПапкуЭлектронныхПисем(ТипПредопределеннойПапки,Владелец)

	Папка = Справочники.ПапкиЭлектронныхПисем.СоздатьЭлемент();
	Папка.УстановитьНовыйКод();
	Папка.ОбменДанными.Загрузка = Истина;
	Папка.ПредопределеннаяПапка = Истина;
	Папка.Наименование = ИмяПредопределеннойПапкиПоТипу(ТипПредопределеннойПапки);
	Папка.ТипПредопределеннойПапки = ТипПредопределеннойПапки;
	Папка.Владелец = Владелец;
	Папка.Записать();

КонецПроцедуры

Функция ИмяПредопределеннойПапкиПоТипу(ТипПредопределеннойПапки)
	
	ИмяПредопределеннойПапки = "";
	
	Если ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Входящие Тогда
		ИмяПредопределеннойПапки = НСтр("ru = 'Входящие'");
	ИначеЕсли ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Исходящие Тогда
		ИмяПредопределеннойПапки = НСтр("ru = 'Исходящие'");
	ИначеЕсли ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Удаленные Тогда
		ИмяПредопределеннойПапки = НСтр("ru = 'Удаленные'");
	ИначеЕсли ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Черновики Тогда
		ИмяПредопределеннойПапки = НСтр("ru = 'Черновики'");
	ИначеЕсли ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Отправленные Тогда
		ИмяПредопределеннойПапки = НСтр("ru = 'Отправленные'");
	ИначеЕсли ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.НежелательнаяПочта Тогда
		ИмяПредопределеннойПапки = НСтр("ru = 'Нежелательная почта'");
	КонецЕсли;
	
	Возврат ИмяПредопределеннойПапки;
	
КонецФункции

// АПК:1391-выкл Для обработчика обновления по заполнению реквизита ТипПредопределеннойПапки.
Функция ТипПредопределеннойПапкиПоИмени(ИмяПредопределеннойПапки) Экспорт
		
	ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.ПустаяСсылка();
	
	Если ИмяПредопределеннойПапки = НСтр("ru = 'Входящие'") Тогда
		ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Входящие;
	ИначеЕсли ИмяПредопределеннойПапки = НСтр("ru = 'Исходящие'")  Тогда
		ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Исходящие;
	ИначеЕсли ИмяПредопределеннойПапки = НСтр("ru = 'Удаленные'") Тогда
		ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Удаленные;
	ИначеЕсли ИмяПредопределеннойПапки = НСтр("ru = 'Черновики'") Тогда
		ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Черновики;
	ИначеЕсли ИмяПредопределеннойПапки = НСтр("ru = 'Отправленные'")  Тогда
		ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.Отправленные;
	ИначеЕсли ИмяПредопределеннойПапки = НСтр("ru = 'Нежелательная почта'") Тогда
		ТипПредопределеннойПапки = Перечисления.ТипыПредопределенныхПапокПисем.НежелательнаяПочта;
	КонецЕсли;
	
	Возврат ТипПредопределеннойПапки;
	
КонецФункции
// АПК:1391-вкл

// Параметры:
//  ВажностьВзаимодействия - ПеречислениеСсылка.ВариантыВажностиВзаимодействия.
//
// Возвращаемое значение:
//  ВажностьИнтернетПочтовогоСообщения
//
Функция ПолучитьВажность(ВажностьВзаимодействия) Экспорт
	
	Если ВажностьВзаимодействия = Перечисления.ВариантыВажностиВзаимодействия.Высокая Тогда
		Возврат ВажностьИнтернетПочтовогоСообщения.Высокая;
	ИначеЕсли ВажностьВзаимодействия = Перечисления.ВариантыВажностиВзаимодействия.Низкая Тогда
		Возврат ВажностьИнтернетПочтовогоСообщения.Низкая;
	Иначе
		Возврат ВажностьИнтернетПочтовогоСообщения.Обычная;
	КонецЕсли;
	
КонецФункции

Функция СобытиеЖурналаРегистрации() Экспорт
	
	Возврат НСтр("ru = 'Взаимодействия'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Получает и добавляет в список значений доступные пользователю учетные записи электронной почты.
//
// Параметры:
//  СписокВыбора  - СписокЗначений - в него будут добавлены доступные пользователю записи электронной почты.
//
Процедура ПолучитьДоступныеУчетныеЗаписиДляОтправки(СписокВыбора,ТаблицаДанныхУчетнойЗаписи) Экспорт
	
	СписокВыбора.Очистить();
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапросаПоДоступнымУчетнымЗаписям();
	
	Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.ТекущийПользователь());
	Результат = Запрос.Выполнить();
	Если Результат.Пустой() Тогда
		Возврат;
	КонецЕсли;
	
	Выборка = Результат.Выбрать();
	Пока Выборка.Следующий() Цикл
		СписокВыбора.Добавить(Выборка.УчетнаяЗапись, 
			ВзаимодействияКлиентСервер.ПолучитьПредставлениеАдресата(Выборка.ИмяПользователя,
			                                                         Выборка.АдресЭлектроннойПочты,
			                                                         ""));
	КонецЦикла;
	
	ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(Результат.Выгрузить(), ТаблицаДанныхУчетнойЗаписи);
	
КонецПроцедуры

Функция ТекстЗапросаПоДоступнымУчетнымЗаписям()
	
	Возврат "
	|ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
	|	ЭлектронноеПисьмоИсходящее.УчетнаяЗапись КАК УчетнаяЗапись
	|ПОМЕСТИТЬ ПоследняяИспользовавшаясяУчетная
	|ИЗ
	|	Документ.ЭлектронноеПисьмоИсходящее КАК ЭлектронноеПисьмоИсходящее
	|ГДЕ
	|	ЭлектронноеПисьмоИсходящее.СтатусПисьма <> ЗНАЧЕНИЕ(Перечисление.СтатусыИсходящегоЭлектронногоПисьма.Черновик)
	|	И НЕ ЭлектронноеПисьмоИсходящее.ПометкаУдаления
	|	И ЭлектронноеПисьмоИсходящее.Автор = &ТекущийПользователь
	|
	|УПОРЯДОЧИТЬ ПО
	|	ЭлектронноеПисьмоИсходящее.Дата УБЫВ
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	УчетныеЗаписиЭлектроннойПочты.Ссылка КАК УчетнаяЗапись,
	|	УчетныеЗаписиЭлектроннойПочты.ИмяПользователя КАК ИмяПользователя,
	|	УчетныеЗаписиЭлектроннойПочты.АдресЭлектроннойПочты КАК АдресЭлектроннойПочты,
	|	ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.УдалятьПисьмаПослеОтправки, ЛОЖЬ) КАК УдалятьПослеОтправки,
	|	ВЫБОР
	|		КОГДА НЕ ПоследняяИспользовавшаясяУчетная.УчетнаяЗапись ЕСТЬ NULL
	|			ТОГДА 0
	|		КОГДА УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)
	|				И УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи = &ТекущийПользователь
	|			ТОГДА 1
	|		КОГДА УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)
	|				И НастройкиУчетныхЗаписейЭлектроннойПочты.ОтветственныйЗаОбработкуПисем = &ТекущийПользователь
	|			ТОГДА 2
	|		ИНАЧЕ 2
	|	КОНЕЦ КАК ЗначениеУпорядочивания
	|ИЗ
	|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиУчетныхЗаписейЭлектроннойПочты КАК НастройкиУчетныхЗаписейЭлектроннойПочты
	|		ПО (НастройкиУчетныхЗаписейЭлектроннойПочты.УчетнаяЗаписьЭлектроннойПочты = УчетныеЗаписиЭлектроннойПочты.Ссылка)
	|		ЛЕВОЕ СОЕДИНЕНИЕ ПоследняяИспользовавшаясяУчетная КАК ПоследняяИспользовавшаясяУчетная
	|		ПО ПоследняяИспользовавшаясяУчетная.УчетнаяЗапись = УчетныеЗаписиЭлектроннойПочты.Ссылка
	|ГДЕ
	|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьДляОтправки
	|	И НЕ УчетныеЗаписиЭлектроннойПочты.ПометкаУдаления
	|	И НЕ ЕСТЬNULL(НастройкиУчетныхЗаписейЭлектроннойПочты.НеИспользоватьВоВстроенномПочтовомКлиенте, ЛОЖЬ)
	|	И (УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи = &ТекущийПользователь
	|			ИЛИ УчетныеЗаписиЭлектроннойПочты.ВладелецУчетнойЗаписи = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка))
	|
	|УПОРЯДОЧИТЬ ПО
	|	ЗначениеУпорядочивания";
	
КонецФункции

// Параметры:
//  УчетнаяЗапись - СправочникСсылка.УчетныеЗаписиЭлектроннойПочты - почта, для которой будут созданы
//                                                                   предопределенные папки.
//
Процедура СоздатьПредопределенныеПапкиЭлектронныхПисемДляУчетнойЗаписи(УчетнаяЗапись) Экспорт
	
	МассивТиповПредопределенныхПапок = Новый Массив;
	МассивТиповПредопределенныхПапок.Добавить(Перечисления.ТипыПредопределенныхПапокПисем.Входящие);
	МассивТиповПредопределенныхПапок.Добавить(Перечисления.ТипыПредопределенныхПапокПисем.Исходящие);
	МассивТиповПредопределенныхПапок.Добавить(Перечисления.ТипыПредопределенныхПапокПисем.Удаленные);
	МассивТиповПредопределенныхПапок.Добавить(Перечисления.ТипыПредопределенныхПапокПисем.Черновики);
	МассивТиповПредопределенныхПапок.Добавить(Перечисления.ТипыПредопределенныхПапокПисем.Отправленные);
	МассивТиповПредопределенныхПапок.Добавить(Перечисления.ТипыПредопределенныхПапокПисем.НежелательнаяПочта);
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	ПапкиЭлектронныхПисем.ТипПредопределеннойПапки
	|ИЗ
	|	Справочник.ПапкиЭлектронныхПисем КАК ПапкиЭлектронныхПисем
	|ГДЕ
	|	ПапкиЭлектронныхПисем.ПредопределеннаяПапка
	|	И ПапкиЭлектронныхПисем.Владелец = &Владелец";
	
	Запрос.УстановитьПараметр("Владелец", УчетнаяЗапись);
	
	МассивИмеющихсяПапок = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("ТипПредопределеннойПапки");
	
	Для каждого ТипПредопределеннойПапки Из МассивТиповПредопределенныхПапок Цикл
		Если МассивИмеющихсяПапок.Найти(ТипПредопределеннойПапки) = Неопределено Тогда
			
			СоздатьПредопределеннуюПапкуЭлектронныхПисем(ТипПредопределеннойПапки, УчетнаяЗапись);
			
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//  Письмо - ДокументСсылка - письмо для которого определяется имя.
//
// Возвращаемое значение:
//  Строка - имя объекта метаданных присоединенных файлов электронного письма.
//  Неопределено
//
Функция ИмяОбъектаМетаданныхПрисоединенныхФайловПисьма(Письмо) Экспорт

	 Если ТипЗнч(Письмо) = Тип("ДокументСсылка.ЭлектронноеПисьмоИсходящее") Тогда
		
		Возврат "ЭлектронноеПисьмоИсходящееПрисоединенныеФайлы";
		
	ИначеЕсли ТипЗнч(Письмо) = Тип("ДокументСсылка.ЭлектронноеПисьмоВходящее") Тогда
		
		Возврат "ЭлектронноеПисьмоВходящееПрисоединенныеФайлы";
		
	Иначе
		
		Возврат Неопределено;
		
	КонецЕсли;

КонецФункции

Процедура СнятьБлокировкуУчетнойЗаписиДляПолучения(УчетнаяЗапись)
	
	НачатьТранзакцию();
	
	Попытка
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЗаблокированныеДляПолученияУчетныеЗаписи");
		ЭлементБлокировки.УстановитьЗначение("УчетнаяЗапись", УчетнаяЗапись);
		Блокировка.Заблокировать();
	
		НаборЗаписей = РегистрыСведений.ЗаблокированныеДляПолученияУчетныеЗаписи.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.УчетнаяЗапись.Установить(УчетнаяЗапись);
		НаборЗаписей.Записать();

		ЗафиксироватьТранзакцию();
		
	Исключение
		
		ОтменитьТранзакцию();
		ВызватьИсключение;
		
	КонецПопытки;
	
КонецПроцедуры

Функция ЗаблокироватьУчетнуюЗапись(УчетнаяЗапись)

	НачатьТранзакцию();
	Попытка
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЗаблокированныеДляПолученияУчетныеЗаписи");
		ЭлементБлокировки.УстановитьЗначение("УчетнаяЗапись", УчетнаяЗапись);
		Блокировка.Заблокировать();
		
		// Проверим блокировку учетной записи и если она доступна для получения, установим блокировку.
		Запрос = Новый Запрос;
		Запрос.Текст = "
		|ВЫБРАТЬ
		|	ЗаблокированныеДляПолученияУчетныеЗаписи.ДатаБлокировки
		|ИЗ
		|	РегистрСведений.ЗаблокированныеДляПолученияУчетныеЗаписи КАК ЗаблокированныеДляПолученияУчетныеЗаписи
		|ГДЕ
		|	ЗаблокированныеДляПолученияУчетныеЗаписи.УчетнаяЗапись = &УчетнаяЗапись";
		
		Запрос.УстановитьПараметр("УчетнаяЗапись", УчетнаяЗапись);
		Выборка = Запрос.Выполнить().Выбрать();
		Если Выборка.Следующий() Тогда
			Если Выборка.ДатаБлокировки + 60 * 60 > ТекущаяДатаСеанса() Тогда
				ЗафиксироватьТранзакцию();
				Возврат Ложь;
			КонецЕсли;
		КонецЕсли;
		
		МенеджерЗаписи = РегистрыСведений.ЗаблокированныеДляПолученияУчетныеЗаписи.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.УчетнаяЗапись  = УчетнаяЗапись;
		МенеджерЗаписи.ДатаБлокировки = ТекущаяДатаСеанса();
		МенеджерЗаписи.Записать();
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	Возврат Истина;
	
КонецФункции

#КонецОбласти
